A COMPUTE! Books Publication
$12.95
The Atari BASIC
A complete explanation of the inside workings of Atari
BASIC, along with the original source code. For
intermediate and advanced programmers.
Bill Wilkinson
Kathleen O'Brien
Paul Laughton
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
-*
1
From COMPUTE! Books and
Optimized Systems Software, Inc.
The Atari BASIC
SOURCE
BOOK
Compiled by Bill Wilkinson
Optimized Systems Software, Inc.
With the assistance of
Kathleen O'Brien and Paul Laughton
COMPUTErPublicationsJnc©
A. Subsidiary 01 American Broadcasting Companies. Inc ^^^^
ATARI is a registered trademark of Atari, Inc.
COMPUTE! Books is a division of COMPUTE! Publications, Inc., a subsidiary of
American Broadcasting Companies, Inc.
Editorial mailing address is:
PO Box 5406
Greensboro, NC 27403 USA
(919) 275-9809
Optimized Systems Services, Inc., is located at:
10379 Lansdale Avenue
Cupertino, CA 95014 USA
(408) 446-3099
All reasonable care has been taken in the writing, testing, and correcting of the text and
of the software within this book. There is, however, no expressed or implied warranty
of any kind from the authors or publishers with respect to the text or software herein
contained. In the event of any damages resulting from the use of the text or the soft-
ware in this book, or from undocumented or documented manufacturer's changes in
Atari BASIC made before or after the publication of this book, the authors or publishers
shall be in no sense liable.
Copyright © 1983 text, COMPUTE! Publications, Inc.
Copyright © 1978, 1979, 1983 program listings, Optimized Systems Software, Inc. All
rights reserved.
Reproduction or translation of any part of this work beyond that permitted by sections
107 and 108 of the United States Copyright Act without the permission of the copyright
owner is unlawful.
Printed in the United States of America
ISBN 0-942386-15-9
10 987654321
II
Table of Contents
Publisher's Foreword v
Acknowledgments vii
Preface ix
Part One: Inside Atari BASIC
1 Atari BASIC: A High-level Language Translator 1
2 Internal Design Overview 7
3 Memory Usage 13
4 Program Editor 25
5 The Pre-compiler 33
6 Execution Overview 49
7 Execute Expression 55
8 Execution Boundary Conditions 71
9 Program Flow Control Statements 75
10 Tokenized Program Save and Load 81
11 The LIST and ENTER Statements 85
12 Atari Hardware Control Statements 91
13 External Data I/O Statements 95
14 Internal I/O Statements 103
15 Miscellaneous Statements 105
16 Initialization 109
Part Two: Directly Accessing Atari BASIC
Introduction to Part Two 113
1 Hexadecimal Numbers 115
2 PEEKing and POKEing 119
3 Listing Variables in Use 123
4 Variable Values 125
5 Examining the Statement Table 129
6 Viewing the Runtime Stack 133
7 Fixed Tokens 135
8 What Takes Precedence? 137
9 Using What We Know 139
Part Three: Atari BASIC Source Code
Source Code Listing 143
iii
Appendices
A Macros in Source Code 273
B The Bugs in Atari BASIC 275
C Labels and Hexadecimal Addresses 281
Index 285
IV
Publisher's
Foreword
It's easy to take a computer language like Atari BASIC for
granted. But every PEEK and POKE, every FOR-NEXT loop
and IF-THEN- branch, is really a miniprogram in itself. Taken
together, they become a powerful tool kit. And, as Atari
owners know, there are few home-computer languages as
powerful and versatile — from editing to execution — as Atari
BASIC.
With this book, the Atari BASIC tool kit is unlocked. The
creators of Atari BASIC and COMPUTE! Publications now offer
you, for the first time, a detailed, inside look at exactly how a
major computer manufacturer's primary language works.
For intermediate programmers, the thorough and careful
explanations in Parts 1 and 2 will help you understand exactly
what is happening in your Atari computer as you edit and run
your programs.
For advanced programmers, Part 3 provides a complete
listing of the source code for Atari BASIC, so that your machine
language programs can make use of the powerful routines built
into that 8K cartridge.
And for programmers at all levels, by the time you're
through studying this book you'll feel that you've seen a whole
computer language at work.
Special thanks are due to Bill Wilkinson, the creative force
behind Atari BASIC and many other excellent programs for
Atari and other computers, for his willingness to share
copyrighted materials with computer users. Readers of
COMPUTE! Magazine already know him as a regular
columnist, and in this book he continues his tradition of clear
explanations and understandable writing.
Acknowledgments
As far as we know, this is the first time that the actual source
listing of a major manufacturer's primary computer language
has been made available to the general public.
As with our previous COMPUTE! Publications book Inside
Atari DOS, this book contains much more than simply a source
listing. All major routines are examined and explained. We
hope that when you finish reading this book you will have a
better understanding of and appreciation for the design and
work which go into as sophisticated a program as Atari BASIC.
This book is the result of the efforts of many people. The
initial credit must go to Richard Mansfield of COMPUTE!
Publications for serving as our goad and go-between. Without
his (and COMPUTE!' s) insistence, this book might never have
been written. Without his patience and guidance, the contents
of this book might not have been nearly as interesting.
To Kathleen O'Brien and Paul Laughton must go the lion's
share of the authoring credits. Between them, they have done
what I believe is a very creditable job of explaining a very
difficult subject, the internal workings of Atari BASIC. In fact,
Part I of this book is entirely their work. Of course, their ability
to explain the listing may not be so surprising. After all,
between them they wrote almost all of the original code for
Atari BASIC. So, even though Paul and Kathleen are not
associated with Optimized Systems Software, we were pleased
to have their invaluable help in writing this book and hope that
they receive some of the credit which has long been due them.
Mike Peters was responsible for taking our old, almost
unreadable copies of the source code diskettes for Atari BASIC
and converting them to another machine, using another
assembler, and formatting the whole thing into an acceptable
form for this book. This isn't surprising either, since Mike
keypunched the original (yes, on cards).
And I am Bill Wilkinson, the one responsible for the rest of
this book. In particular, I hope you will find that a good
amount of the material in Part II will aid you in understanding
how to make the best use of this book.
Vll
The listing of Atari BASIC is reproduced here courtesy of
OSS, Inc., which now owns its copyright and most other
associated rights.
Vlll
Preface
In 1978, Atari, Inc., purchased a copy of Microsoft BASIC for
the 6502 microprocessor (similar to the version from which
Applesoft is derived). After laboring for quite some time, the
people of Atari still couldn't make it do everything they wanted
it to in the ROM space they had available. And there was a
deadline fast approaching: the January 1979 Las Vegas
Consumer Electronics Show (CES).
At that time, Kathleen, Paul, Mike and I all worked for
Shepardson Microsystems, Inc. (SMI). Though little known
by the public, SMI was reasonably successful in producing
some very popular microcomputer software, including the
original Apple DOS, Cromemco's 16K and 32K BASICs, and
more. So it wasn't too surprising that Atari had heard of us.
And they asked us: Did we want to try to fix Microsoft
BASIC for them? Well, not really. Did we think we could write
an all-new BASIC in a reasonable length of time? Yes. And
would we bet a thousand dollars a week on our ability to do so?
While Bob Shepardson negotiated with Atari and I wrote
the preliminary specifications for the language (yes, I'm the
culprit), time was passing all too rapidly. Finally, on 6 October
1978, Atari's Engineering Department gave us the okay to
proceed.
The schedule? Produce both a BASIC and a Disk File
Manager (which became Atari DOS) in only six months. And,
to make sure the pressure was intense, they gave us a $1000-a-
week incentive (if we were early) or penalty (if we were late).
But Paul Laughton and Kathleen O'Brien plunged into it.
And, although the two of them did by far the bulk of the work,
there was a little help from Paul Krasno (who implemented the
transcendental routines), Mike Peters (who did a lot of
keypunching and operating), and me (who designed the
floating point scheme and stood around in the way a lot). Even
Bob Shepardson got into the act, modifying his venerable
IMP-16 assembler to accept the special syntax table mnemonics
that Paul invented (and which we paraphrase in the current
listing via macros).
IX
Atari delivered the final signed copy of the purchase order
on 28 December 1978, two and a half months into the project.
But it didn't really matter: Paul and Kathy were on vacation,
having delivered the working product more than a week
before !
So Atari took Atari BASIC to CES, and Shepardson
Microsystems faded out of the picture. As for the bonus for
early delivery — there was a limit on how much the incentive
could be. Darn.
The only really unfortunate part of all this was that Atari
got the BASIC so early that they moved up their ROM
production schedule and committed to a final product before
we had a chance to do a second round of bug fixing.
And now? Mike and I are running Optimized Systems
Software, Inc. And even though Paul and Kathleen went their
own way, we have kept in touch enough to make this book
possible.
Part One
How Atari
BASIC Works
-I
Chapter One
Atari BASIC:
A High-Level Language
Translator
The programming language which has become the de facto
standard for the Atari Home Computer is the Atari 8K BASIC
Cartridge, known simply as Atari BASIC. It was designed to
serve the programming needs of both the computer novice and
the experienced programmer who is interested in developing
sophisticated applications programs. In order to meet such a
wide range of programming needs, Atari BASIC was designed
with some unique features.
In this chapter we will introduce the concepts of high level
language translators and examine the design features of Atari
BASIC that allow it to satisfy such a wide variety of needs.
Language Translators
Atari BASIC is what is known as a high level language translator.
A language, as we ordinarily think of it, is a system for
communication. Most languages are constructed around a set
of symbols and a set of rules for combining those symbols.
The English language is a good example. The symbols are
the words you see on this page. The rules that dictate how to
combine these words are the patterns of English grammar.
Without these patterns, communication would be very
difficult, if not impossible: Out sentence this believe, of make
don't this trying if sense you to! If we don't use the proper
symbols, the results are also disastrous: @twu2 yeggopt
gjsiem, keorw?
In order to use a computer, we must somehow
communicate with it. The only language that our machine
really understands is that strange but logical sequence of ones
and zeros known as machine language. In the case of the Atari,
this is known as 6502 machine language.
When the 6502 central processing unit (CPU) "sees" the
sequence 01001000 in just the right place according to its rules
of syntax, it knows that it should push the current contents of
Chapter One
the accumulator onto the CPU stack. (If you don't know what
an "accumulator" or a "CPU stack" is, don't worry about it.
For the discussion which follows, it is sufficient that you be
aware of their existence.)
Language translators are created to make it simpler for
humans to communicate with computers. There are very few
6502 programmers, even among the most expert of them, who
would recognize 01001000 as the push-the-accumulator
instruction. There are more 6502 programmers, but still not
very many, who would recognize the hexadecimal form of
01001000, $48, as the push-the-accumulator instruction.
However, most, if not all, 6502 programmers will recognize the
symbol PHA as the instruction which will cause the 6502 to
push the accumulator.
PHA, $48, and even 01001000, to some extent, are
translations from the machine's language into a language that
humans can understand more easily. We would like to be able
to communicate to the computer in symbols like PHA; but if
the machine is to understand us, we need a language translator
to translate these symbols into machine language.
The Debug Mode of Atari's Editor/ Assembler cartridge, for
example, can be used to translate the symbols $48 and PHA to
the ones and zeros that the machine understands. The
debugger can also translate the machine's ones and zeros to
$48 and PHA. The assembler part of the Editor/ Assembler
cartridge can be used to translate entire groups of symbols like
PHA to machine code.
Assemblers
An assembler — for example, the one contained in the
Assembler/Editor cartridge — is a program which is used to
translate symbols that a human can easily understand into the
ones and zeros that the machine can understand. In order for
the assembler to know what we want it to do, we must
communicate with it by using a set of symbols arranged
according to a set of rules. The assembler is a translator, and
the language it understands is 6502 assembly language.
The purpose of 6502 assembly language is to aid program
authors in writing machine language code. The designers of
the 6502 assembly language created a set of symbols and rules
that matches 6502 machine language as closely as possible.
This means that the assembler retains some of the
Chapter One
disadvantages of machine language. For instance, the process
of adding two large numbers takes dozens of instructions in
6502 machine language. If human programmers had to code
those dozens of instructions in the ones and zeros of machine
language, there would be very few human programmers.
But the process of adding two large numbers in 6502
assembly language also takes dozens of instructions. The
assembly language instructions are easier for a programmer to
read and remember, but they still have a one-to-one cor-
respondence with the dozens of machine language
instructions. The programming is easier, but the process
remains the same.
High Level Languages
High level languages, like Atari BASIC, Atari PILOT, and Atari
Pascal, are simpler for people to use because they more closely
approximate human speech and thought patterns. However,
the computer still understands only machine language. So the
high level languages, while seeming simple to their users, are
really much more complex in their internal operations than
assembly language.
Each high level language is designed to meet the specific
need of some group of people. Atari Pascal is designed to
implement the concept of structured programming. Atari
PILOT is designed as a teaching tool. Atari BASIC is designed
to serve both the needs of the novice who is just learning to
program a computer and the needs of the expert programmer
who is writing a sophisticated application program, but wants
the program to be accessible to a large number of users.
Each of these languages uses a different set of symbols and
symbol-combining rules. But all these language translators
were themselves written in assembly language.
Language Translation Methods
There are two different methods of performing language
translation — compilation and interpretation. Languages which
translate via interpretation are called interpreters. Languages
which translate via compilation are called compilers.
Interpreters examine the program source text and simulate
the operations desired. Compilers translate the program source
text into machine language for direct machine execution.
Chapter One
The compilation method tends to produce faster, more
efficient programs than does the interpretation method.
However, the interpretation method can make programming
easier.
Problems with the Compiler Method
The compiler user first creates a program source file on a disk,
using a text editing program. Then the compiler carefully
examines the source program text and generates the machine
language as required. Finally, the machine language code is
loaded and executed. While this three-step process sounds
fairly simple, it has several serious "gotchas."
Language translators are very particular about their
symbols and symbol-combining rules. If a symbol is
misspelled, if the wrong symbol is used, or if the symbol is not
in exactly the right place, the language translator will reject it.
Since a compiler examines the entire program in one gulp, one
misplaced symbol can prevent the compiler from
understanding any of the rest of the program — even though
the rest of the program does not violate any rules! The result is
that the user often has to make several trips between the text
editor and the compiler before the compiler successfully
generates a machine language program.
But this does not guarantee that the program will work. If
the programmer is very good or very lucky, the program will
execute perfectly the very first time. Usually, however, the user
must debug the program.
This nearly always involves changing the source program,
usually many times. Each change in the source program sends
the user back to step one: after the text editor changes the
program, the compiler still has to agree that the changes are
valid, and then the machine code version must be tested again.
This process can be repeated dozens of times if the program is
very complex.
Faster Programming or Faster Programs?
The interpretation method of language translation avoids many
of these problems. Instead of translating the source code into
machine language during a separate compiling step, the
interpreter does all the translation while the program is running.
This means that whenever you want to test the program you're
writing, you merely have to tell the interpreter to run it. If
things don't work right, stop the program, make a few
changes, and run the program again at once.
Chapter One
You must pay a few penalties for the convenience of using
the interpreter's interactive process, but you can generally
develop a complex program much more quickly than the
compiler user can.
However, an interpreter is similar to a compiler in that the
source code fed to the interpreter must conform to the rules of
the language. The difference between a compiler and an
interpreter is that a compiler has to verify the symbols and
symbol-combining rules only once — when the program is
compiled. No evaluation goes on when the program is
running. The interpreter, however, must verify the symbols
and symbol-combining rules every time it attempts to run the
program. If two identical programs are written, one for a
compiler and one for an interpreter, the compiled program will
generally execute at least ten to twenty times faster than the
interpreted program.
Pre-compiling Interpreter
Atari BASIC has been incorrectly called an interpreter. It does
have many of the advantages and features of an interpretive
language translator, but it also has some of the useful features
of a compiler. A more accurate term for Atari's BASIC
Language Translator is pre-compiling interpreter.
Atari BASIC, like an interpreter, has a text editor built into
it. When the user enters a source line, though, the line is not
stored in text form, but is translated into an intermediate code,
a set of symbols called tokens. The program is stored by the
editor in token form as each program line is entered. Syntax
and symbol errors are weeded out at that time.
Then, when you run the program, these tokens are
examined and their functions simulated; but because much of
the evaluation has already been done, the execution of an Atari
BASIC program is faster than that of a pure interpreter. Yet
Atari BASIC'S program-building process is much simpler than
that of a compiler.
Atari BASIC has advantages over compilers and
interpreters alike. With Atari BASIC, every time you enter a
line it is verified for language correctness. You don't have to
wait until compilation; you don't even have to wait until a test
run. When you type RUN you already know there are no
syntax errors in your program.
Chapter Two
r
r
Internal Design
Overview
Atari BASIC is divided into two major functional areas: the
Program Constructor and the Program Executor. The Program
Constructor is used when you enter and edit a BASIC program.
The source line pre-compiler, also part of the Program
Constructor, translates your BASIC program source text lines
into tokenized lines. The Program Executor is used to execute
the tokenized program — when you type RUN, the Program
Executor takes over.
Both the Program Constructor and the Program Executor
are designed to use data tables. Some of these tables are
already contained in BASIC'S ROM (read-only memory).
Others are constructed by BASIC in the user RAM (random-
access memory). Understanding these various tables is an
important key to understanding the design of Atari BASIC.
Tokens
In Atari BASIC, tokens are the intermediate code into which
the source text is translated. They represent source-language
symbols that come in various lengths — some as long as 100
characters (a long variable name) and others as short as one
character (" + " or "-"). Every token, however, is exactly one
eight-bit byte in length.
Since most BASIC Language Symbols are more than one
character long, the representation of a multi-character BASIC
Language Symbol with a single-byte token can mean a
considerable saving of program storage space.
A single-byte token symbol is also easier for the Program
Executor to recognize than a multi-character symbol, since it
can be evaluated by machine language routines much more
quickly. The SEARCH routine — 76 bytes long — located at
$A462 is a good example of how much assembly language it
takes to recognize a multi-character symbol. On the other
hand, the two instructions located at $AB42 are enough to
Chapter Two
determine if a one-byte token is a variable. Because routines to
recognize Atari BASIC'S one-byte tokens take so much less
machine language, they execute relatively quickly.
The 256 possible tokens are divided into logical numerical
groups that also make them simpler to deal with in assembly
language. For example, any token whose value is 128 ($80) or
greater represents a variable name. The logical grouping of the
token values also means faster execution speeds, since, in
effect, the computer only has to check bit 7 to recognize a
variable.
The numerical grouping of the tokens is shown below:
Token Value (Hex) Description
00-0D Unused
0E Floating Point Numeric Constant.
The next six bytes will hold its value.
OF String Constant.
The next byte is the string length.
A string of that length follows.
10-3C Operators.
See table starting at $A7E3 for specific
operators and values.
3D-54 Functions.
See table starting at $A820 for specific
functions and values.
55-7F Unused.
80-FF Variables.
In addition to the tokens listed above, there is another set
of single-byte tokens, the Statement Name Tokens. Every
statement in BASIC starts with a unique statement name, such
as LET, PRINT, and POKE. (An assignment statement such as
" A = B + C, " without the word LET, is considered to begin with
an implied LET.) Each of these unique statement names is
represented by a unique Statement Name Token.
The Program Executor does not confuse Statement Name
Tokens with the other tokens because the Statement Name
Tokens are always located in the same place in every statement
— at the beginning. The Statement Name Token value is
derived from its entry number, starting with zero, in the
Statement Name Table at $A4AF.
Chapter Two
Tables
A table is a systematic arrangement of data or information.
Tables in Atari BASIC fall into two distinct types: tables that are
part of the Atari BASIC ROM and tables that Atari BASIC
builds in the user RAM area.
ROM Tables
The following is a brief description of the various tables in the
Atari BASIC ROM. The detailed use of these tables will be
explained in subsequent chapters.
Statement Name Table ($A4AF). The first two bytes in each
entry point to the information in the Statement Syntax Table
for this statement. The rest of the entry is the name of the
statement name in ATASCII. Since name lengths vary, the last
character of the statement name has the most significant bit
turned on to indicate the end of the entry. The value of the
Statement Name Token is derived from the relative (from zero)
entry number of the statement name in this table.
Statement Execution Table ($AA00). Each entry in this table
is the two-byte address of the 6502 machine language code
which will simulate the execution of the statement. This table is
organized with the statements in the same order as the
statements in the Statement Name Table. Therefore, the
Statement Name Token can be used as an index to this table.
Operator Name Table ($A7E3). Each entry comprises the
ATASCII text of an Operator Symbol. The last character of each
entry has the most significant bit turned on to indicate the end
of the entry. The relative (from zero) entry number, plus 16
($10), is the value of the token for that entry. Each of the entries
is also given a label whose value is the value of the token for
that symbol. For example, the ";" symbol at $A7E8 is the fifth
(from zero) entry in the table. The label for the ";" token is
CSC, and the value of CSC is $15, or 21 decimal (1*16 + 5).
Operator Execution Table ($AA70). Each two-byte entry
points to the address, minus one, of the routine which
simulates the execution of an operator. The token value, minus
16, is used to access the entries in this table during execution
time. The entries in this table are in the same order as in the
Operator Name Table.
Operator Precedence Table ($AC3F). Each entry
represents the relative execution precedence of an individual
operator. The table entries are accessed by the operator tokens,
r
Chapter Two
minus 16. Entries correspond with the entries in the Operator
Name Table. (See Chapter 7.)
Statement Syntax Table ($A60D). Entries in this table are
used in the process of translating the source program to tokens.
The address pointer in the first part of each entry in the
Statement Name Table is used to access the specific syntax
information for that statement in this table. (See Chapter 5.)
RAM Tables
The tables that BASIC builds in the user RAM area will be
explained in detail in Chapter 3. The following is a brief
description of these tables:
Variable Name Table. Each entry contains the source
ATASCII text for the corresponding user variable symbol in the
program. The relative (from zero) entry number of each entry
in this table, plus 128, becomes the value of the token
representing the variable.
Variable Value Table. Each entry either contains or points
to the current value of a variable. The entries are accessed by
the token value, minus 128.
Statement Table. Each entry is one tokenized BASIC
program line. The tokenized lines are kept in this table in
ascending numerical order by line number.
Array/String Table. This table contains the current values
for all strings and numerical arrays. The location of the specific
values for each string and/or array variable is accessed from
information in the Variable Value Table.
Runtime Stack. This is the LIFO Runtime Stack, used to
control the execution of GOSUB/RETURN and similar
statements.
Pre-compiler
Atari BASIC translates the BASIC source lines from text to
tokens as soon as they are entered. To do this, Atari BASIC
must recognize the symbols of the BASIC Language. BASIC
also requires that its symbols be combined in certain specific
patterns. If the symbols don't follow the required patterns,
then Atari BASIC cannot translate the line. The process of
checking a source line for the required symbol patterns is called
syntax checking.
BASIC performs syntax checking as part of the tokenizing
process. When the Program Editor receives a completed line of
10
'
Chapter Two
input, the editor hands the line to the syntax routine, which
examines the first word of the line for a statement name. If a
valid statement name is not found, then the line is assumed to
be an implied LET statement.
The grammatical rules for each statement are contained in
the Statement Syntax Table. A special section of code examines
the symbols in the source line, under the direction of the
grammatical rules set forth in the Statement Syntax Table. If
the source line does not conform to the rules, then it is reported
back as an error. Otherwise, the line is translated to tokens.
The result of this process is returned to the Program Editor for
further processing.
Program Editor
When Atari BASIC is not executing statements, it is in the edit
mode. When the user enters a source line and hits return, the
editor accepts the line into a line buffer, where it is examined
by the pre-compiler. The pre-compiler returns either tokens or
an error text line.
If the line started with a line number, the editor inserts the
tokenized line into the Statement Table. If the Statement Table
already contains a line with the same line number, then the old
line is removed from the Statement Table. The new line is then
inserted just after the statement with the next lower line
number and just before the statement with the next higher line
number.
If the line has no line number, the editor inserts the line at
the end of the Statement Table. It then passes control to the
Program Executor, which will carry out the statement(s) in the
line at the end of the Statement Table.
Program Executor
The Program Executor has a pointer to the statement that it is to
execute. When control is passed to the executor, the pointer
points to the direct (command) line at the end of the statement
table. If that statement causes some other line to be executed
(RUN, GOTO, GOSUB, etc.), the pointer is changed to the
new line. Lines continue to be executed as long as nothing
stops that execution (END, STOP, error, etc.). When the
program execution is stopped, the Program Executor returns
control to the editor.
11
Chapter Two
When a statement is to be executed, the Statement Name
Token (the first code in the statement) directs the interpreter to
the specific code that executes that statement. For instance, if
that token represents the PRINT statement, the PRINT
execution code is called. The execution code for each statement
then examines the other tokens and simulates their operations.
Execute Expression
Arithmetic and logical expressions (A + B, C/D + E, F<G, etc.)
are simulated with the Execute Expression code. Expression
operators ( + ,-,*, etc.) have execution precedence — some
operators must be executed before some others. The
expression 1 + 3*4 has a value of 13 rather than 16
because * had a higher precedence than + . To properly
simulate expressions, BASIC rearranges the expression with
higher precedence first.
BASIC uses two temporary storage areas to hold parts of
the rearranged expression. One temporary storage area, the
Argument Stack, holds arguments — values consisting of
constants, variables, and temporary values resulting from
previous operator simulations. The other temporary storage
area, the Operator Stack, holds operators. Both temporary
storage areas are managed as Last-In/First-Out (LIFO) stacks.
LIFO Stacks
A LIFO (Last In/First Out) stack operates on the principle that
the last object placed in the stack storage area will be the first
object removed from it. If the letters A, B, C, and D, in that
order, were placed in a LIFO stack, then D would be the first
letter removed, followed by C, B, and A. The operations
required to rearrange the expression using these stacks will be
explained in Chapter 7.
BASIC also uses another LIFO stack, the Runtime Stack, in
the simulation of statements such as GOSUB and FOR.
GOSUB requires that BASIC remember where in the statement
table the GOSUB was located so it will return to the right spot
when RETURN is executed. If more than one GOSUB is
executed before a RETURN, BASIC returns to the statement
after the most recent GOSUB.
12
Chapter Three
Memory Usage
Many of BASIC'S functions are controlled by a set of tables
built in RAM not already occupied by BASIC or the Operating
System (OS). Figure 3.1 is a diagram of memory use by both
programs. Every time a BASIC programmer enters a statement,
memory requirements for the RAM tables change. Memory use
by the OS also varies. Different graphics modes, for example,
require different amounts of memory.
These changing memory requirements are monitored, and
this series of pointers keeps BASIC and the OS from overlaying
each other in memory:
• High memory address (HMADR) at location $02E5
• Application high memory (APHM) at location $000E
• Low memory address (LMADR) at location $02E7
When a graphics mode requires larger screen space, the OS
checks the application high memory address (APHM) that has
been set by BASIC. If there is enough room for the new screen,
the OS uses the upper portion of space and sets the pointer
HMADR to the bottom of the screen to tell the application how
much space the OS is now using.
BASIC builds its table toward high memory from low
memory. The pointer to the lowest memory available to an
application, called LMADR in the BASIC listing, is set by the
OS to tell BASIC the lowest memory address that BASIC can
use. When BASIC needs more room for one of its tables,
BASIC checks HMADR. If there is enough room, BASIC uses
the space and puts the highest address it has used into APHM
for OS.
BASIC'S operation consists primarily of building, reading,
and modifying tables. Pointers to the RAM tables are kept in
consecutive locations in zero page starting at $80. These tables
are, in order,
• Multipurpose Buffer
• Variable Name Table
• Variable Value Table
• String/ Array Table
13
Chapter Three
• Statement Table
• Runtime Stack
BASIC reserves space for a buffer at LM ADR. It then builds
the tables contiguously (without gaps), starting at the top of the
buffer and extending as far as necessary towards APHM. When
a new entry needs to be added to a table, all data in the tables
above is moved upward the exact amount needed to fit the new
entry into the right place.
Figure 3-1. Memory Usage
FFFF
E000
D800
D000
BFFF
A000
Operating System
ROM
Floating Point
ROM
Hardware Registers
Unused
BASIC ROM
Screen
HMADR
Free RAM
0000
BASIC
RAM
Tables
Operating System
RAM
APHM
LMADR
14
Chapter Three
Variable Name Table
The Variable Name Table (VNT) is built during the pre-compile
process. It is read, but not modified, during execution — but
only by the LIST statement. The VNT contains the names of the
variables used in the program in the order in which they were
entered.
The length of entries in the Variable Name Table depends
on the length of the variable name. The high order bit of the
last character of the name is on. For example, the ATASCII code
for the variable name ABC is 41 42 43 (expressed in
hexadecimal). In the Variable Name Table it looks like this:
41 42 C3
The $ character of a string name and the ( character of an
array element name are stored as part of the variable name. The
table entries for variables C, AA$, and X(3) would look like
this:
C C3
AA$ 41 41 A4
X(3) 58 A8
It takes only two bytes to store X(3) because this table stores
onlyX(.
A variable is represented in BASIC by a token. The value of
this token is the position (relative to zero) of the variable name
in the Variable Name Table, plus $80. BASIC references an
entry in the table by using the token, minus $80, as an index.
The Variable Name Table is not changed during execution time.
The zero page pointer to the Variable Name Table is called
VNTP in the BASIC listing.
Variable Value Table
The Variable Value Table (VVT) is also built during the pre-
compile process. It is both read and modified during execution.
There is a one-to-one correspondence in the order of entries
between the Variable Name Table and the Variable Value Table.
If XXX is the fifth variable in the Variable Name Table, then
XXX's value is the fifth entry in the Variable Value Table.
BASIC references a table entry by vising the variable token,
minus $80, as an index.
Each entry in the Variable Value Table consists of eight
bytes. The first two bytes have the following meaning:
15
Chapter Three
1
2
type vnum
type = one byte, which indicates the type of variable
$00 for floating point variable
$40 for array variable
$80 for string variable
vnum = one byte, which indicates the relative position of the
variable in the tables
The meaning of the next six bytes varies, depending on the
type of variable (floating point, string, or array). In all three
cases, these bytes are initialized to zero during syntaxing and
during the execution of the RUN or CLR.
When the variable is a floating point number, the six bytes
represent its value.
When the variable is an array, the remaining six bytes have
the following format:
1
2
3 4
5 6
7 8
1
1
1
1
1
1
disp
dim 1
dim!
disp diml dim2
= the two-byte displacement into string/array space of
this array variable
= two bytes indicating the first dimension value
= two bytes indicating the second dimension value
All three of these values are set appropriately when the array is
DIMensioned during execution.
When the variable is a string, the remaining six bytes have
the following meaning:
1
2
3 4
5 6
7 8
1
1
1
1
1
1
disp curl maxl
16
Chapter Three
disp = the two-byte displacement into string/ array space of
this string variable. This value is set when the string is
DIMensioned during execution.
curl = the two-byte current length of the string. This value
changes as the length of the string changes during
execution.
maxl = the two-byte maximum possible length of this string.
This value is set to the DIM value during execution.
When either a string or an array is DIMensioned during
execution, the low-order bit in the type byte is turned on, so
that the array type is set to $41 and the string type to $81.
The zero page pointer to the Variable Value Table is called
VVTP in the BASIC listing.
Statement Table
The Statement Table, built as each statement is entered during
editing, contains tokenized forms of the statements that were
entered. This table determines what happens during
execution.
The format of a Statement Table entry is shown in Figure
3-2. There can be several tokens per statement and several
statements per line.
Figure 3-2. Format of a Statement Table Entry
lnum Hen slen snt
toks eos slen snt
toks
eos eol
lnum = the two-byte line number (low-order, high-order)
lien = the one-byte line length (the displacement to the next
line in the table)
slen = the one-byte statement length (the displacement to
the next statement in the line)
snt = the one-byte Statement Name Token
toks = the other tokens that make up the statement (this
is variable in length)
eos = the one-byte end of statement token
eol = the one-byte end of line token
The zero page pointer to the Statement Table is called
STMTAB in the BASIC listing.
17
Chapter Three
String/Array Table
The String/ Array Table (also called String/ Array Space) is
created and modified during execution. Strings and arrays can
be intermixed in the table, but they have different formats.
Each array or string is pointed to by an entry in the Variable
Value Table. The entry in the String/ Array Table is created
when the string or array is DIMensioned during execution. The
data in the entry changes during execution as the value of the
string or an element of the array changes.
An entry in the String/Array Table is not initialized to any
particular value when it is created. The elements of arrays and
the characters in a string cannot be counted upon to have any
particular value. They can be zero, but they can also be garbage
— data previously stored at those locations.
Array Entry
For an array, the String/ Array Table contains one six-byte entry
for each array element. Each element is a floating point
number, stored in raveled order. For example, the entry in the
String/ Array Table for an array that was dimensioned as A(l,2)
contains six elements, in this order:
A(0,0) A(0,1) A(0,2) A(1,0) A(l,l) A(l,2)
String Entry
A string entry in the String/ Array Table is created during
execution, when the string is DIMensioned. The size of the
entry is determined by the DIM value. The "value" of the
string to BASIC at any time is determined by the data in the
String/ Array Table and the current length of the string as set in
the Variable Value Table.
The zero page pointer to the String/ Array Table is called
STARP in the BASIC listing.
The Runtime Stack is created during execution. BASIC uses
this LIFO stack to control processing of FOR/NEXT loops and
GOSUBs. When either a FOR or a GOSUB statement is
encountered during execution, an entry is put on the Runtime
Stack. When a NEXT, RETURN, or a POP statement is
encountered, entries are pulled off the stack.
Both the FOR entry and the GOSUB entry have a four-byte
header:
18
Chapter Three
type lnum disp
type = one byte indicating the type of element
GOSUB type =
FOR type = non-zero
lnum = the two-byte number of the line which contains the
statement (low-order, high-order)
disp = one byte indicating the displacement into the line in
the Statement Table of the token which caused this
stack entry.
The FOR-type byte is actually the token representing the
loop control variable from the FOR statement. (In the statement
FOR I = 1 to 10, 1 is the loop control variable.) So the FOR-type
byte will have a value of $80 through $FF — the possible values
of a variable token.
The FOR entry contains 12 additional bytes, formatted like
this:
2 3 4 5 6
J L
9 10 11 12
— I 1 1
J L
sval
step
sval = the six-byte (floating point) limit value at which to
stop the loop
step = the six-byte (floating point) STEP value to increment
by
The GOSUB entry consists entirely of the four-byte header.
The LIST and READ statements also put a GOSUB type entry
on the Runtime Stack, so that the line containing the LIST or
READ can be found again when the statement has finished
executing.
The zero page pointer to the Runtime Stack is called
RUNSTK in the BASIC listing.
19
Chapter Three
VNTP
$82, $83
VNTD
$84, $85
WTP
$86, $87
STMTAB
$88, $89
STMCUR
$8A, $8B
STARP
$8C, $8D
RUNSTK
$8E, $8F
MEMTOP
$90, $91
Zero Page Table Pointers
The starting addresses of the tables change dynamically during
both program construction and program execution. BASIC
keeps the current start addresses of the tables and other
pointers required to manage memory space in contiguous zero-
page cells. Each pointer is a two-byte address, low byte first.
Since these zero page cell addresses remain constant,
BASIC is always able to find the tables. Here are the zero page
pointers used in memory management, their names in the
BASIC listing, and their addresses:
Multipurpose Buffer
Variable Name Table
VNT dummy end
Variable Value Table
Statement Table
Current Statement Pointer
String/Array Table
Runtime Stack
Top of used memory
Memory Management Routines
Memory Management routines allocate space to the BASIC
tables as needed. There are two routines: expand, to add space,
and contract, to delete space. Each routine has one entry point
for cases in which the number of bytes to be added or deleted is
less than 256, and another when it is greater than or equal to
256.
The EXPAND and CONTRACT routines often move many
thousands of bytes each time they are called. The 6502
microprocessor is designed to move fewer than 256 bytes of
data very quickly. When larger blocks of data are moved, the
additional 6502 instructions required can make the process very
slow. The EXPAND and CONTRACT routines circumvent this
by using the less-than-256-byte fast-move capabilities in the
movement of thousands of bytes. The end result is a set of very
fast and very complex data movement routines.
All of this complexity does have a drawback. The infamous
Atari BASIC lock-up problem lives in these two routines. If an
EXPAND or CONTRACT requires that an exact multiple of 256
bytes be moved, then the routines move things from the wrong
20
Chapter Three
place in memory to the wrong place in memory, whereupon
the computer locks up and won't respond. The only way to
avoid losing hours of work this way is to SAVE to disk or
cassette frequently.
EXPAND ($A881)
Parameters at entry:
register
X = the zero page address containing the pointer to
the location after which space is to be added
Y = the low-order part of the number of bytes to
expand
A = the high-order part of the number of bytes to
expand
The routine creates a hole in the table memory, starting at a
requested location and continuing the requested number of
bytes.
The routine first checks to see that there is enough free
memory space to satisfy the request.
It adds the requested expand size to each of the zero-page
table pointers between the one pointed to by the X register and
MEMTOP. Then each pointer will point to the correct address
when EXPAND is done.
EXPAND then creates space at the address indicated by the
X register. The number of bytes required is contained in the Y
and A registers. (Y contains the least significant byte, while A
contains the most significant.) All data from the requested
address to the address pointed to by MEMTOP is moved
toward high memory by the requested number of bytes. This
creates a hole of the proper size.
The routine then sets Application High Memory (APHM)
to the value in MEMTOP. This tells the OS the highest memory
address that BASIC is currently using.
EXPLOW ($A87F)
Parameters at entry:
register
X = zero page address containing the pointer to the
location after which space is to be added
Y = number of bytes to expand (low-order byte only)
21
Chapter Three
This is an additional entry point for the EXPAND routine. It
is used when the number of bytes to be added to the table is
less than 256.
This routine first loads the 6502 accumulator with zero to
indicate the most significant byte of the expand length. It then
functions exactly like EXPAND.
CONTRACT ($A8FD)
Parameters at entry:
register
X = zero page address containing the pointer to the
starting location where space is to be removed
Y = the low-order part of the number of bytes to
contract
A = the high-order part of the number of bytes to
contract
This routine removes a requested number of bytes at a
requested location by moving all the data from higher in the
tables downward the exact amount needed to replace the
unwanted bytes.
It subtracts the requested contract size from each of the
zero page table pointers between the one pointed to by the X
register and MEMTOP. Then each pointer will point to the
correct address when CONTRACT is done.
The routine sets application high memory (APHM) to the
value in MEMTOP to indicate to the OS the highest memory
address that BASIC is currently using.
The block of data to be moved downward is defined by
starting at the address pointed to by the zero-page address
pointed to in X, plus the offset number stored in Y and A, and
then continuing to the address specified at MEMTOP. Each
byte of data in that block is moved downward in memory by
the number of bytes specified in Y and A, effectively erasing all
the data between the specified address and that address plus
the requested offset.
CONTLOW ($A8FB)
Parameters at entry:
register
X = the zero page address containing the pointer to
the location at which space is to be removed
22
Chapter Three
Y = the number of bytes to contract (low-order byte
only)
This routine is used to remove fewer than 256 bytes from
the tables at a requested location by moving all the data from
higher in the tables downward the exact amount needed to
replace the unwanted bytes.
This routine first loads the 6502 accumulator with zero to
serve as the most significant byte of the contract length. It then
functions exactly like CONTRACT.
Miscellaneous Memory Allocations
Besides the tables, which change dynamically, BASIC also uses
buffers and stacks at fixed locations.
The Argument/Operator Stack is allocated at BASIC'S low
memory address and occupies 256 bytes. During pre-compiling
it is used as the output buffer for the tokens. During execution,
it is used while evaluating an expression. This buffer/stack is
referenced by a pointer at location $80. This pointer has several
names in the BASIC listing: LOMEM, ARGOPS, ARGSTK,
and OUTBUFF.
The Syntax Stack is used during the process of syntaxing a
statement. It is referenced directly — that is, not through a
pointer. It is located at $480 and is 256 bytes long.
The Line Buffer is the storage area where the statement is
placed when it is ENTERed. It is the input buffer for the edit
and pre-compile processes. It is 128 bytes long and is
referenced directly as LBUFF. Often the address of LBUFF is
also put into INBUFF so that the buffer can be referenced
through a pointer, though INBUFF can point to other locations
during various phases of BASIC'S execution.
23
Chapter Four
Program Editor
The Atari keyboard is the master control panel for Atari BASIC.
Everything BASIC does has its origins at this control panel. The
Program Editor's job is to service the control panel and respond
to the commands that come from it.
The editor gets a line from the user at the keyboard; does
some preliminary processing on the line; passes the line to the
pre-compiler for further processing; inserts, deletes, or
replaces the line in the Statement Table; calls the Program
Executor when necessary; and then waits to receive the user's
next line input.
Line Processing
The Program Editor, which starts at $A060, begins its process
by resetting the 6502 CPU stack. Resetting the CPU stack is a
drastic operation that can only occur at the beginning of a
logical process. Each time Atari BASIC prepares to get a new
line from the user, it restarts its entire logical process.
Getting a Line
The Program Editor gets a user's line by calling CIO. The origin
of the line is transparent to the Program Editor. The line may
have been typed in at the keyboard or entered from some
external device like the disk (if the ENTER command was
given). The Program Editor simply calls CIO and asks it to put a
line of not more than 255 bytes into the buffer pointed to by
INBUFF ($F3). INBUFF points to the 128-byte area defined at
LBUFF($580).
The OS's screen editor, which is involved in getting a line
from the keyboard, will not pass BASIC a line that is longer
than 120 bytes. Normally, then, the 128-byte buffer at LBUFF is
big enough to contain the user's line.
Sometimes, however, if a line was originally entered from
the keyboard with few blanks and many abbreviations, then
LISTed to and re-ENTERed from the disk, an input line may be
longer than 128 bytes. When this happens, data in the $600
page is overlaid. A LINE TOO LONG error will not necessarily
25
r
Chapter Four
occur at this point. A LINE TOO LONG error occurs only if the
Pre-compiler exceeds its stack while processing the line or if
the tokenized line OUTBUFF exceeds 256 bytes. These
overflows depend on the complexity of the line rather than on
its actual length.
When CIO has put a line into the line buffer (LBUFF) and
the Program Editor has regained control, it checks to see if the
user has changed his mind and hit the break key. If the user did
indeed hit break, the Program Editor starts over and asks CIO
for another line.
Flags and Indices
In order to help control its processing, the Program Editor uses
flags and indices. These must be given initial values.
CIX and COX. The index CIX ($F2) is used to access the user's
input line in the line buffer (LBUFF), while COX ($94) is used to
access the tokenized statement in the output buffer
(OUTBUFF). These buffers and their indices are also used by
the pre-compiler. The indices are initialized to zero to indicate
the beginning of the buffers.
DIRFLG. This flag byte ($A6) is used by the editor to remember
whether a line did or did not have a line number, and also to
remember if the pre-compiler found an error in that line.
DIRFLG is initialized to zero to indicate that the line has a line
number and that the pre-compiler has not found an error.
MAXCIX. This byte ($9F) is maintained in case the line contains
a syntax error. It indicates the displacement into LBUFF of the
error. The character at this location will then be displayed in
inverse video. The Program Editor gives this byte the same
initial value as CIX, which is zero.
SWNTP. The pointer to the current top of the Variable Name
Table (VNTD) is saved as SWNTP ($AD) so that if there is a
syntax error in this line, any variables that were added can be
removed. If a user entered an erroneous line, such as 100
A = XAND B, the variable XAND would already have been
added to the variable tables before the syntax error was
discovered. The user probably meant to enter 100 A = X AND B,
and, since there can only be 128 variables in BASIC, he
probably does not want the variable XAND using up a place in
the variable tables. The Program Editor uses SWNTP to find
the entry in the Variable Name Table so it can be removed.
26
Chapter Four
SVVVTE. The process used to indicate which variable entries to
remove from the Variable Value Table in case of error is
different. The number of new variables in the line
(SVWTE,$B1) is initialized to zero. The Program Pre-compiler
increments the value every time it adds a variable to the
Variable Value Table. If a syntax error is detected, this number
is multiplied by eight (the number of bytes in each entry on the
Variable Value Table) to get the number of bytes to remove,
counting backward from the most recent value entered.
Handling Blanks
In many places in the BASIC language, blanks are not
significant. For example,
100 IFX = 6THENGOTO500
has the same meaning as
100 IF X = 6 THEN GOTO 500.
The Program Editor, using the SKIPBLANK routine
($DBA1), skips over unnecessary blanks.
Processing the Line Number
Once the editor has skipped over any leading blanks, it begins
to examine the input line, starting with the line number. The
floating point package is called to determine if a line number is
present, and, if so, to convert the ATASCII line number to a
floating point number. The floating point number is converted
to an integer, saved in TSLNUM for later use, and stored in the
tokenized line in the output buffer (OUTBUFF).
The routine used to store data into OUTBUFF is called
:SETCODE ($A2C8). When :SETCODE stores a byte into
OUTBUFF, it also increments COX, that buffer's index.
BASIC could convert the ATASCII line number directly to
an integer, but the routine to do this would not be used any
other time. Routines to convert ATASCII to floating point and
floating point to integer already exist in BASIC for other
purposes. Using these existing routines conserves ROM space.
An interesting result of this sequence is that it is valid to
enter a floating point number as a line number. For example,
100.1, 10.9, or 2.05E2 are valid line numbers. They would be
converted to 100, 11, and 205 respectively.
If the input line does not start with a line number, the line
is considered to be a direct statement. DIRFLG is set to $80 so
27
Chapter Four
that the editor can remember this fact. The line number is set to
32768 ($8000). This is one larger than the largest line number a
user is allowed to enter. BASIC later makes use of this fact in
processing the direct statement.
Line length. The byte after the line number in the tokenized
line in OUTBUFF is reserved so that the line length (actually
the displacement to the next line) can be inserted later. (See
Chapter 2.) The routine :SETCODE is called to reserve the byte
by incrementing (COX) to indicate the next byte.
Saving erroneous lines. In the byte labeled STMSTRT, the
Program Editor saves the index into the line buffer (LBUFF) of
the first non-blank character after the line number. This index
is used only if there is a syntax error, so that all the characters
in the erroneous line can be moved into the tokenized line
buffer and from there into the Statement Table.
There are advantages to saving an erroneous line in the
Statement Table, because you can LIST the error line later. The
advantage is greatest, not when entering a program at the
keyboard, but when entering a program originally written in a
different BASIC on another machine (via a modem, perhaps).
Then, when a line that is not correct in Atari BASIC is entered,
the line is flagged and stored — not discarded. The user can
later list the program, find the error lines, and re-enter them
with the correct syntax for Atari BASIC.
Deleting lines. If the input line consists solely of a line number,
the Program Editor deletes the line in the Statement Table
which has that line number. The deletion is done by pointing to
the line in the Statement Table, getting its length, and calling
CONTRACT. (See Chapter 3.)
Statement Processing
The user's input line may consist of one or more statements.
The Program Editor repeats a specific set of functions for each
statement in the line.
Initializing
The current index (COX) into the output buffer (OUTBUFF) is
saved in a byte called STMLBD. A byte is reserved in
OUTBUFF by the routine :SETCODE. Later, the value in
28
Chapter Four
STMLBD will be used to access this byte, and the statement
length (the displacement to the next statement) will be stored
here.
Recognizing the Statement Name
After the editor calls SKBLANK to skip blanks, it processes the
statement name, now pointed to by the input index (CIX). The
editor calls the routine SEARCH ($A462) to look for this
statement name in the Statement Name Table. SEARCH saves
the table entry number of this statement name into location
STENUM.
The entry number is also the Statement Name Token value,
and it is stored into the tokenized output buffer (OUTBUFF) as
such by :SETCODE. The SEARCH routine also saves the
address of the entry in SRC ADR for use by the pre-compiler.
If the first word in the statement was not found in the
Statement Name Table, the editor assumes that the statement
is an implied LET, and the appropriate token is stored. It is left
to the pre-compiler to determine if the statement has the
correct syntax for LET.
The editor now gives control to the pre-compiler, which
places the appropriate tokens in OUTBUFF, increments the
indices CIX and COX to show current locations, and indicates
whether a syntax error was detected by setting the 6502 carry
flag on if there was an error and clearing the carry flag if there
was not. (See Chapter 5.)
If a Syntax Error Is Detected
If the 6502 carry flag is set when the editor regains control, the
editor does error processing.
In MAXCIX, the pre-compiler stored the displacement
into LBUFF at which it detected the error. The Program Editor
changes the character at this location to inverse video.
The character in inverse video may not be the point of error
from your point of view, but it is where the pre-compiler
detected an error. For example, assume you entered X = YAND
Z. You probably meant to enter X = Y AND Z, and therefore
would consider the error to be between Y and AND. However,
since YAND is a valid variable name, X = YAND is a valid
BASIC statement.
The pre-compiler doesn't know there is an error until it
encounters B. The value of highlighting the error with inverse
29
Chapter Four
video is that it gives the user an approximation of where the
error is. This can be a big advantage, especially if the input line
contained multiple statements or complex expressions.
The next thing the editor does when a syntax error has
been detected is set a value in DIRFLG to indicate this fact for
future reference. Since the DIRFLG byte also indicates whether
this is a direct statement, the error indicator of $40 is ORed with
the value already in DIRFLG.
The editor takes the value that it saved in STMSTRT and
puts it into CIX so that CIX now points to the start of the first
statement in the input line in LBUFF. STMLBD is set to indicate
the location of the first statement length byte in OUTBUFF. (A
length will be stored into OUTBUFF at this displacement at a
later time.)
The editor sets the index into OUTBUFF (COX) to indicate
the Statement Name Token of the first statement in OUTBUFF,
and stores a token at that location to indicate that this line has a
syntax error. The entire line (after the line number) is moved
into OUTBUFF. At this point COX indicates the end of the line
in OUTBUFF. (Later, the contents of OUTBUFF will be moved
to the Statement Table.)
This is the end of the special processing for an erroneous
line. The process that follows is done for both correct and
erroneous lines.
Final Statement Processing
During initial line processing, the Program Editor saved in
STMLBD a value that represents the location in OUTBUFF at
which the statement length (displacement to the next
statement) should be stored. The Program Editor now retrieves
that value from STMLBD. Using this value as an index, the
editor stores the value from COX in OUTBUFF as the
displacement to the next statement.
The Program Editor checks the next character in LBUFF. If
this character is not a carriage return (indicating end of the
line), then the statement processing is repeated. When the
carriage return is found, COX will be the displacement to the
next line. The Program Editor stores COX as the line length at a
displacement of two into OUTBUFF.
30
Chapter Four
Statement Table Processing
The final tokenized form of the line exists in OUTBUFF at this
point. The Program Editor's next task is to insert or replace the
line in the Statement Table.
The Program Editor first needs to create the correct size
hole in the Statement Table. The editor calls the GETSTMT
routine ($A9A2) to find the address where this line should go
in the Statement Table. If a line with the same line number
already exists, the routine returns with the address in
STMCUR and with the 6502 carry flag off. Otherwise, the
routine puts the address where the new line should be inserted
in the Statement Table into STMCUR and turns on the 6502
carry flag. (See Chapter 6.)
If the line does not exist in the Statement Table, the editor
loads zero into the 6502 accumulator. If the line does exist, the
editor calls the GETLL routine ($A9DD) to put the line length
into the accumulator. The editor then compares the length of
the line already in the Statement Table (old line) with the
length of the line in OUTBUFF (new line).
If more room is needed in the Statement Table, the editor
calls the EXPLOW ($A87F; see Chapter 3). If less space is
needed for the new line, it calls a routine to point to the next
line (GNXTL, at location $A9D0; see Chapter 6), and then calls
the CONTLOW ($A8FB; see Chapter 3).
Now that we have the right size hole, the tokenized line is
moved from OUTBUFF into the Statement Table at the location
indicated by STMCUR.
Line Wrap-up
After the line has been added to the Statement Table, the editor
checks DIRFLG for the syntax error indicator. If the second
most significant bit ($40) is on, then there is an error.
Error Wrap-up
If there is an error, the editor removes any variables that were
added by this line by getting the number of bytes that were
added to the Variable Name Table and the Variable Value Table
from SWNTP and SWVTE. It then calls CONTRACT ($A8FD)
to remove the bytes from each table.
Next, the editor lists the line. The Statement Name Token,
which was set to indicate an error, causes the word "ERROR"
31
Chapter Four
to be printed. An inverse video character indicates where the
error was detected. The editor now waits for you to enter
another line.
Handling Correct Lines
If the line was syntactically correct, the editor again examines
DIRFLG. In earlier processing, the most significant bit ($80) of
this byte was set on if the line was a direct statement. If it is not
a direct statement, then the editor is finished with the line, and
it waits for another input line.
If the line is a direct statement, earlier processing already
assigned it a line number of 32768 ($8000), one larger than the
largest line number a user can enter. Since lines are arranged in
the Statement Table in ascending numerical order, this line will
have been inserted at the end of the table. The current
statement pointer (STMCUR— $8A, $8B) points to this line.
The Program Editor transfers control to a Program Executor
routine, Execution Control (EXECNL at location $A95F), which
will handle the execution of the direct statement. (See
Chapter 6.)
32
Chapter Five
The Pre-compiler
The symbols and symbol-combining rules of Atari BASIC are
coded into Syntax Tables, which direct the Program Pre-
compiler in examining source code and producing tokens. The
information in the Syntax Tables is a transcription of a meta-
language definition of Atari BASIC.
The Atari BASIC Meta-language
A meta-language is a language which describes or defines
another language. Since a meta-language is itself a language, it
also has symbols and symbol-combining rules — which define
with precision the symbols and symbol-combining rules of the
subject language.
Atari BASIC is precisely defined with a specially developed
meta-language called the Atari BASIC Meta-language, or
ABML. (ABML was derived from a commonly used compiler-
technology meta-language called BNF.) The symbols and
symbol-combining rules of ABML were intentionally kept very
simple.
Making Up a Language
To show you how ABML works, we'll create an extremely
simple language called SAP, for Simple Arithmetic Process.
SAP symbols consist of variables, constants, and operators.
• Variables: The letters A, B, and C only.
• Constants: The numbers 1,2,3,4,5,6,7,8, and 9 only.
• Operators: The characters +,-,*, /, and ! only. Of
course, you already know the functions of all
the operators except "!". The character ! is a
pseudo-operator of the SAP language used
to denote the end of the expression, like the
period that ends this sentence.
The grammar of the SAP language is precisely defined by
the ABML definition in Figure 5-1.
33
Chapter Five
Figure 5-1. The SAP Language Expressed in ABML
SAP
< expression >
< operation >
< value >
< constant >
< variable >
< operator >
< expression > !
< value > < operation > |
< operator > < expression >
< constant > | < variable >
1|2|3|4|5|6|7|8|9
A I B I C
+
/
The ABML symbols used to define the SAP language in Figure
5-1 are:
: = is defined as
or
< > label
terminal
symbols
Whatever is on the left of : = is defined as
consisting of whatever is on the right of : = ,
and in that order.
The symbol | allows choices for what
something is defined as. For instance, in the
sixth line < variable > can be A or B or C.
If | does not appear between two symbols,
then there is no choice. For example, in the
second line < expression > must have both
< value > and < operation >, in that order,
to be valid.
Whatever comes between < and > is an
ABML label. All labels, as non-terminal
symbols, must be defined at some point,
though the definitions can be circular —
notice that < operation > is part of the
definition of < expression > in the second
line, while in the third line < expression >
is part of the definition of < operation > .
Symbols used in definitions, which are not
enclosed by < and > and are also not one
of the ABML symbols, are terminal symbols
in the language being defined by ABML. In
SAP, some terminal symbols are A, !, B, *,
and 1. They cannot be defined as consisting
of other symbols — they are themselves the
symbols that the SAP language manipu-
34
Chapter Five
lates, and must appear exactly as they are
shown to be valid in SAP. In effect, they are
the vocabulary of the SAP language.
Statement Generation
The ABML description of SAP can be used to generate
grammatically correct statements in the SAP language. To do
this, we merely start with the first line of the definition and
replace the non-terminal symbols with the definitions of those
symbols. The replacement continues until only terminal
symbols remain. These remaining terminal symbols constitute
a grammatically correct SAP statement.
Since the or statement requires that one and only one of the
choices be used, we will have to arbitrarily replace the non-
terminal with the one valid choice.
Figure 5-2 illustrates the ABML statement generation
process.
Figure 5-2. The Generation of One Possible SAP
Statement
(J)
SAP :
(2)
SAP :
(3)
SAP :
(4)
SAP :
(5)
SAP :
(6)
SAP :
(7)
SAP :
(8)
SAP :
(9)
SAP :
(10)
SAP :
(11)
SAP
(12)
SAP
(13)
SAP
(14)
SAP
(15)
SAP
< expression > !
< value > < operation > !
< variable > < operation > !
B < operation > !
B < operator > < expression > !
B*< expression > !
B* < value > < operation > !
B* < constant > < operation > !
B*4< operation > !
B*4 < operator > < expression > !
B*4 + < expression > !
B*4 + < value > < operation > !
B*4+ < variable > < operation >!
B*4 + C < operation > !
B*4 + C!
~
In (2), < value >< operation > replaces < expression >
because the ABML definition of SAP (Figure 5-1) defines
< expression > as < value > < operation >.
In (3), the non-terminal < value > is replaced with
35
Chapter Five
< variable > . The definition of < value > gives two choices for
the substitution of < value > . We happened to choose
< variable > .
In (4), we reach a terminal symbol, and the process of
defining < value > ends. We happened to choose B to replace
< variable > .
In (5), we go back and start defining < operation > . There
are two choices for the replacement of < operation > , either
< operator > < expression > or nothing at all (since there is
nothing to the right of I in the second line of Figure 5-1). If
nothing had been chosen, then (5) would have been: SAP : =B!
The statement B! has no further non-terminals; the process
would have been finished, and a valid statement would have
been produced. Instead we happened to choose
< operator > < expression > .
The SAP definition for < expression > is
< value > < operation > . If we replace < operation > with its
definition we get:
< expression > : = < value > < operator > < expression >
The definition of < expression > includes < expression >
as part of its definition. If the < operator > < expression >
choice were always made for < operation > , then the process
of replacement would never stop. A SAP statement can be
infinitely long by definition. The only thing which prevents us
from always having an infinitely long SAP statement is that
there is a second choice for the replacement of < operation > :
nothing.
The replacements in (5) and (10) reflect the repetitive
choices of defining < expression > in terms of itself. The choice
in (15) reflects the nothing choice and thus finishes the
replacement process.
Computerized Statement Generation
If we slightly modify our procedure for generating statements,
we will have a process that could be easily programmed into a
computer. Instead of arbitrarily replacing the definition of non-
terminals, we can think of the non-terminal as a GOSUB.
When we see <X> :=<Y><Z>,we can think of < Y > as
being a subroutine-type procedure:
(a) Go to the line that has < Y > on the left side .
(b) Process the definition (right side) of < Y > .
36
Chapter Five
(c) If while processing the definition of < Y > , other non-
terminals are found, GOSUB to them.
(d) If while processing the definition of < Y > we
encounter a terminal, output the terminal symbol as the
next symbol of the generated statement.
(e) When the definition of < Y > is finished, return to the
place that < Y> was called from and continue.
Since ABML is structured so that it can be programmed, a
fascinating exercise is to design a simple English sentence
grammar with ABML, then write a BASIC program to generate
valid English sentences at random. The randomness of the
sentences would be derived by using the RND function to
select from the definitions or choices. An example of such a
grammar is shown in Figure 5-3. (The programming exercise is
left to you.)
Figure 5-3. A Simple English Sentence Grammar in ABML
SENTENCE : = < subject > < adverb > < verb > < object > .
< subject > : = The < adjective > < noun >
< verb > : = eats | sleeps | drinks | talks | hugs
< adverb > : = quickly | silently | slowly | viciously |
lovingly f sadly |
< object > := at home | in the car | at the table | at
school | < subject >
<noun> := boy | girl | dog | programmer | computer
| teacher
< adjective > := happy | sad | blue | light | round | smart
| cool | nice |
Syntactical Analysis
The process of examining a language statement for
grammatical correctness is called syntactical analysis, or
syntaxing.
Statement verification is similar to statement generation.
Instead of arbitrarily choosing which or definition to use,
however, the choices are already made, and we must check to
see whether the statement symbols are used in valid patterns.
To do this, we must process through each or definition until we
find a matching valid terminal symbol.
The result of statement generation is a valid, grammatically
correct statement, but the result of statement verification is a
37
Chapter Five
statement validity indication, which is a simple yes or no. Either
the statement is grammatically correct or it is not. Failure
occurs when some statement symbol cannot be matched with a
valid terminal symbol under the rules of the grammar.
The Reporting System
To use the pass/fail result of statement verification, we must
build a reporting system into the non-terminal checking
process. Whenever we, in effect, GOSUB to a non-terminal
definition, that non-terminal definition must report its pass/fail
status.
A fail status is generated and returned by a non-terminal
definition when it finds no matching terminal for the current
statement symbol. If the current statement symbol is B and the
< constant > definition in the SAP language is called, then
< constant > would report a fail status to the routine that
called it.
A pass status is returned when a terminal symbol is found
which matches the current statement symbol. If our current
statement symbol had been 7 instead of B, then < constant >
would have reported pass.
Whenever such a match does occur, we return to the
statement, and the next symbol to the right becomes the new
current symbol for examination and verification.
Cycling Through the Definitions
In SAP, the < constant > definition is called from the < value >
definition. If < constant > reports fail, then we examine the
next or choice, which is < variable > . The current symbol is B,
so < variable > reports pass.
Since at least one of the or choices of < value > has
reported pass, < value > will report pass to its caller. If both
< constant > and < variable > had reported fail, then
< value > would report fail to its caller.
The caller of < value > is < expression > . If < value >
reports pass, < operation > is called. If < operation > reports
pass, then < expression > can report pass to its caller. If either
< value > or < operation > reports fail, then < expression >
must report fail, since there are no other or choices for
< expression > .
The definition of < operation > contains a special pass/ fail
property. If either < operator > or < expression > reports fail,
38
Chapter Five
then the or choice must be examined. In this case the or choice
is nothing. The or nothing means something special: report pass,
but do not advance to the next symbol.
The final pass/fail report is generated from the first line of
the definition. If < expression > reports pass and the next
symbol is !, then SAP reports pass. If either one of these
conditions has a fail status, then SAP must report fail to
whatever called SAP from outside the language.
Backing Up
Sometimes it is necessary to back up over symbols which have
already been processed. Let's assume that there was a
definition of the type <X> : = <Y>|<Z>.Itis possible that
while < Y > is attempting to complete its definition, it will find
a number of valid matching terminal symbols before it
discovers a symbol that it cannot match. In this case, < Y >
would have consumed a number of symbols before it decided
to report fail. All of the symbols that < Y > consumed must be
unconsumed before <Z> can be called, since <Z> will need
to check those same symbols.
The process of unconsuming symbols is called backup.
Backup is usually performed by the caller of < Y > , which
remembers which source symbol was current when it called
< Y > . If < Y > reports fail, then the caller of < Y > restores the
current symbol pointer before calling < Z > .
Locating Syntax Error
When a final report oifail is given for a statement, it is often
possible to guess where the error occurred. In a left-to-right
system, the symbol causing the failure is usually the symbol
which follows the rightmost symbol found to be valid. If we
keep track of the rightmost valid symbol during the various
backups, we can report a best guess as to where the failure-
causing error is located. This is exactly what Atari BASIC does
with the inverse video character in the ERROR line.
For simplicity, our example was coded for SAP, but the
syntactical analysis we have just described is essentially the
process that the Atari BASIC pre-compiler uses to verify the
grammar of a source statement. The Syntax Tables are an
ABML description of Atari BASIC. The pre-compiler, also
known as the syntaxer, contains the routines which verify
BASIC statements.
39
Chapter Five
Statement Syntax Tables
There is one entry in the Syntax Tables for each BASIC
statement. Each statement entry in the Syntax Table is a
transcription of an ABML definition of the grammar for that
particular statement. The starting address of the table entry for
a particular statement is pointed to by that statement's entry in
the Statement Name Table.
The data in the Syntax Tables is very much like a computer
machine language. The pseudo-computer which executes this
pseudo-machine language is the pre-compiler code. Like any
machine language, the pseudo-machine language of the Syntax
Tables has instructions and instruction operands. For example,
an ABML non-terminal symbol is transcribed to a code which
the pre-compiler executes as a type of "GO SUB and report
pass/fail" command.
Here are the pseudo-instruction codes in the Syntax Tables;
each is one byte in length.
Absolute Non-Terminal Vector
Name: ANTV
Code: $00
This is one of the forms of the non-terminal GOSUB. It is
followed by the address, minus 1, of the non-terminal's
definition within the Syntax Table. The address is two bytes
long, with the least significant byte first.
External Subroutine Call
Name: ESRT
Code: $01
This instruction is a special type of terminal symbol
checker. It is followed by the address, minus 1, of a 6502
machine language routine. The address is two bytes long, with
the least significant byte first. The ESRT instruction is a dens ex
machina — the "god from the machine" who solved
everybody's problems at the end of classical Greek plays.
There are some terminals whose definition in ABML would be
very complex and require a great many instructions to describe.
In these cases, we go outside the pseudo-machine language of
the Syntax Tables and get help from 6502 machine language
routines — the dens ex machina that quickly gives the desired
40
Chapter Five
result. A numeric constant is one example of where this outside
help is required.
ABML or
Name: OR
Value: $02
This is the familiar ABML or symbol ( | ). It provides for an
alternative definition of a non-terminal.
Return
Name: RTN
Value: $03
This code signals the end of an ABML definition line.
When we write an ABML statement on paper, the end of a
definition line is obvious — there is no further writing on the
line. When ABML is transcribed to machine codes, the
definitions are all pushed up against each other. Since the
function that is performed at the end of a definition is a return,
the end of definition is called return (RTN).
Unused (Codes $04 through $0D are unused.)
Expression Non-Terminal Vector
Name: VEXP
Value: $0E
The ABML definition for an Atari BASIC expression is
located at $A60D. Nearly every BASIC statement definition
contains the possibility of having < expression > as part of it.
VEXP is a single-byte call to < expression > , to avoid wasting
the two extra bytes that ANTV would take. The pseudo-
machine understands that this instruction is the same as an
ANTV call to < expression > at$A60D.
Change Last Token
Name: CHNG
Value: $0F
This instruction is followed by a one-byte change to token
value. The operator token instructions cause a token to be
placed into the output buffer. Sometimes it is necessary to
change the token that was just produced. For example, there
are several = operators. One = operator is for the assignment
41
Chapter Five
statement LET X = 4. Another = operator is for comparison
operations like IF Y = 5. The pseudo-machine will generate the
assignment = token when it matches = . The context of the
grammar at that point may have required a comparison = token.
The CHNG instruction rectifies this problem.
Operator Token
Name: (many)
Value: $10 through $7F
These instructions are terminal codes for the Atari BASIC
Operators. The code values are the values of each operator
token. The values, value names, and operator symbols are
defined in the Operator Name Table (see Chapter 2).
When the pseudo-machine sees these terminal symbol
representations, it compares the symbol it represents to the
current symbol in the source statement. If the symbols do not
match, then/fl/7 status is generated. If the symbols match, then
pass status is generated, the token (instruction value) is placed
in the token output buffer, and the next statement source
symbol becomes the current symbol for verification.
Relative Non-Terminal Vectors
Name: (none)
Value: $80 - $BF (Plus)
$C0 - $FF (Minus)
This instruction is similar to ANTV, except that it is a single
byte. The upper bit is enough to signal that this one-byte code
is a non-terminal GOSUB. The destination address of the
GOSUB is given as a position relative to the current table
location. The values $80 through $BF correspond to an address
which is at the current table address plus $00 through $3F. The
values $C0 through $FF correspond to an address which is at
the current table address minus $01 through $3F.
Pre-compiler Main Code Description
The pre-compiler, which starts at SYNENT ($A1C3), uses the
pseudo-instructions in the Syntax Tables to verify the
correctness of the source line and to generate the tokenized
statements.
42
Chapter Five
Syntax Stack
The pre-compiler uses a LIFO stack in its processing. Each time
a non-terminal vector ("GOSUB") is executed, the pre-
compiler must remember where the call was made from. It
must also remember the current locations in the input buffer
(source statement) and the output buffer (tokenized statement)
in case the called routine reports fail and backup is required.
This LIFO stack is called the Syntax Stack.
The Syntax Stack starts at $480 at the label SIX. The stack is
256 bytes in size. Each entry in the stack is four bytes long. The
stack can hold 64 levels of non-terminal calls. If a sixty-fifth
stack entry is attempted, the LINE TOO LONG error is
reported. (This error should be called LINE TOO COMPLEX,
but the line is most likely too long also.)
The first byte of each stack entry is the current input index
(CIX). The second byte is the current output index (COX). The
final two bytes are the current address within the syntax tables.
The current stack level is managed by the STKLVL ($A9)
cell. STKLVL maintains a value from $00 to $FC, which is the
displacement to the current top of the stack entry.
Initialization
The editor has saved an address in SRC ADR ($96). This
address is the address, minus 1, of the current statement's
ABML instructions in the Syntax Tables. The current input
index (CIX) and the current output index (COX) are also preset
by the editor.
The initialization code resets the syntax stack manager
(STKLVL) to zero and loads the first stack entry with the values
in CIX, COX, and CPC — the current program counter, which
holds the address of the next pseudo-instruction in the Syntax
Tables.
PUSH
Values are placed on the stack by the PUSH routine ($A228).
PUSH is entered with the new current pseudo-program
counter value on the CPU stack. PUSH saves the current CIX,
COX, and CPC on the syntax stack and increments STKLVL.
Next, it sets a new CPC value from the data on the CPU stack.
Finally, PUSH goes to NEXT.
43
Chapter Five
POP
Values are removed from the stack with the POP routine
($A252). POP is entered with the 6502 carry flag indicating
pass/fail. If the carry is clear, then pass is indicated. If the carry is
set, then/flf/ is indicated.
POP first checks STKLVL. If the current value is zero, then
the pre-compiler is done. In this case, POP returns to the editor
via RTS. The carry bit status informs the editor of the pass/ fail
status.
If STKLVL is not zero, POP decrements STKLVL.
At this point, POP examines the carry bit status. If the carry
is clear (pass), POP goes to NEXT. If the carry is set (fail), POP
goes to FAIL.
NEXT and the Processes It Calls
After initialization is finished and after each Syntax Table
instruction is processed, NEXT is entered to process the next
syntax instruction.
NEXT starts by calling NXSC to increment CPC and get the
next syntax instruction into the A register. The instruction
value is then tested to determine which syntax instruction code
it is and where to go to process it.
If the Syntax Instruction is OR ($02) or RTN ($03), then exit
is via POP. When POP is called due to these two instructions,
the carry bit is always clear, indicating pass.
ERNTV. If the instruction is RNTV ("GOSUB " $80 - $FF),
then ERNTV ($A201) is entered. This code calculates the new
CPC value, then exits via PUSH.
GETADR. If the instruction is ANTV ($00) or the deus ex
machina ESRT ($01) instruction, then GETADR is called.
GETADR obtains the following two-byte address from the
Syntax Table.
If the instruction was ANTV, then GETADR exits via
PUSH.
If the instruction was ESRT, then GETADR calls the
external routine indicated. The external routine will report
pass/fail via the carry bit. The pass/fail condition is examined at
$A1F0. If pass is indicated, then NEXT is entered. If fail is
indicated, then FAIL is entered.
TERMTST. If the instruction is VEXP ($0E), then the code at
$A1F9 will go to TERMTST ($A2A9), which will cause the code
44
Chapter Five
at $A2AF to be executed for VEXP. This code obtains the
address, minus 1, of the ABML for the < expression > in the
Syntax Table and exits via PUSH.
ECHNG. If the instruction was CHNG ($0F), then ECHNG
($A2BA) is entered via tests at $A1F9 and $A2AB. ECHNG will
increment CPC and obtain the change-to token which will then
replace the last previously generated token in OUTBUFF.
ECHNG exits via RTS, which will take control back to NEXT.
SRCONT. The Operator Token Instructions ($10-$7F) are
handled by the SRCONT routine. SRCONT is called via tests at
$A1F9 and $A2AD. SRCONT will examine the current source
symbol to see if it matches the symbol represented by the
operator token. When SRCONT has made its determination, it
will return to the code at $A1FC. This code will examine the
pass/fail (carry clear/set) indicator returned by SRCONT and
take the appropriate action. (The SRCONT routine is detailed
on the next page.)
FAIL
If any routine returns a fail indicator, the FAIL code at $A26C
will be entered. FAIL will sequentially examine the
instructions, starting at the Syntax Table address pointed to by
CPC, looking for an OR instruction.
If an OR instruction is found, the code at $A27D will be
entered. This code first determines if the current statement
symbol is the rightmost source symbol to be examined thus far.
If it is, it will update MAXCIX. The editor will use MAXCIX to
set the inverse video flag if the statement is erroneous. Second,
the code restores CIX and COX to their before-failure values
and goes to NEXT to try this new OR choice.
If, while searching for an OR instruction, FAIL finds a RTN
instruction, it will call POP with the carry set. Since the carry is
set, POP will re-enter FAIL once it has restored things to the
previous calling level.
All instruction codes other than OR and RTN are skipped
over by FAIL.
45
Chapter Five
Pre-compiler Subroutine Descriptions
SRCONT ($A2E6)
The SRCONT code will be entered when an operator token
instruction is found in the Syntax Tables by the main pre-
compiler code. The purpose of the routine is to determine if the
current source symbol in the user's line matches the terminal
symbol represented by the operator token. If the symbols
match, the token is placed into the output buffer and pass is
returned. If the symbols do not match, fail is returned.
SRCONT uses the value of the operator token to access the
terminal symbol name in the Operator Name Table. The
characters in the source symbol are compared to the characters
in the terminal symbol. If all the characters match, pass is
indicated.
TNVAR, TSVAR ($A32A)
These deus ex machina routines are called by the ESRT
instruction. The purpose of the routines is to determine if the
current source symbol is a valid numeric (TNVAR) or string
(TSVAR) variable. If the source symbol is not a valid variable,
fail is returned.
When pass is indicated, the routine will put a variable token
into the output buffer. The variable token ($80-$FF) is an index
into the Variable Name Table and the Variable Value Table,
plus $80.
The Variable Name Table is searched. If the variable is
already in the table, the token value for the existing variable is
used. If the variable is not in the table, it will be inserted into
both tables and a new token value will be used.
A source symbol is considered a valid variable if it starts
with an alphabetic character and it is not a symbol in the
Operator Name Table, which includes all the reserved words.
The variable is considered to be a string if it ends with $;
otherwise it is a numeric variable. If it is a string variable, $ is
stored with the variable name characters.
The routine also determines if the variable is an array by
looking for (. If the variable is an array, ( is stored with the
variable name characters in the Variable Name Table. As a
result, ABC, ABC$, and ABC(n) are all recognized as different
variables.
46
Chapter Five
TNCON ($A400)
TNCON is called by the ESRT instruction. Its purpose is to
examine the current source symbol for a numeric constant,
using the floating point package. If the symbol is not a numeric
constant, the routine returns fail.
If the symbol is a numeric constant, the floating point
package has converted it to a floating point number. The
resulting six-byte constant is placed in the output buffer
preceded by the $0E numeric constant token. The routine then
exits with pass indicated.
TSCON ($A428)
TSCON is called by the ESRT instruction. Its purpose is to
examine the current symbol for a string constant. If the symbol
is not a string constant, the routine returns fail.
If the first character of the symbol is ", the symbol is a
string constant. The routine will place the string constant token
($0F) into the output buffer, followed by a string length byte,
followed by the string characters.
The string constant consists of all the characters that follow
the starting double quote up to the ending double quote. If the
EOL character ($9B) is found before the ending double quote,
an ending double quote is assumed. The EOL is not part of the
string. The starting and ending double quotes are not saved
with the string. All 256 character codes except $9B (EOL) and
$22 (") are allowed in the string.
SEARCH ($A462)
This is a general purpose table search routine used to find a
source symbol character string in a table.
The table to be searched is assumed to have entries which
consist of a fixed length part (0 to 255 bytes) followed by a
variable length ATASCII part. The last character of the ATASCII
part is assumed to have the most significant bit ($80) on. The
last table entry is assumed to have the first ATASCII character
as $00.
Upon entry, the X register contains the length of the fixed
part of the table (0 to 255). The A, Y register pair points to the
start of the table to be searched. The source string for
comparison is pointed to by INBUFF plus the value in CIX.
Upon exit, the 6502 carry flag is clear if a match was found,
and set if no match was found. The X register points to the end
47
Chapter Five
of the symbol, plus 1, in the buffer. The SRCADR ($95) two-
byte cell points to the matched table entry. STENUM ($AF)
contains the number, relative to zero, of the matched table
entry.
SETCODE (A2C8)
The SETCODE routine is used to place a token in the next
available position in the output (token) buffer. The value in
COX determines the current displacement into the token
buffer. After the token is placed in the buffer, COX is
incremented by one. If COX exceeds 255, the LINE TOO
LONG error message is generated.
48
Chapter Six
Execution Overview
During the editing and pre-compiling phase, the user's
statements were checked for correct syntax, tokenized, and put
into the Statement Table. Then direct statements were passed
to the Program Executor for immediate processing, while
program statements awaited later processing by the Program
Executor.
We now enter the execution phase of Atari BASIC. The
Program Executor consists of three parts: routines which
simulate the function of individual statement types; an
expression execution routine which processes expressions (for
example, A + B + 3, A$(l,3), "HELP", A(3) + 7.26E-13); and the
Execution Control routine, which manages the whole process.
Execution Control
Execution Control is invoked in two situations. If the user
has entered a direct statement, Execution Control does some
initial processing and then calls the appropriate statement
execution routine to simulate the requested operation. If the
user has entered RUN as a direct statement, the statement
execution routine for RUN instructs Execution Control to start
processing statements from the beginning of the statement
table.
When the editor has finished processing a direct statement,
it initiates the Execution Control routine EXECNL ($A95F).
Execution Control's job is to manage the process of statement
simulation.
The editor has saved the address of the statement it
processed in STMCUR and has put the statement in the
Statement Table. Since this is a direct statement, the line
number is $8000, and the statement is saved as the last line in
the Statement Table.
The fact that a direct statement is always the last statement
in the Statement Table gives a test for the end of a user's
program.
The high- order byte of the direct statement line number
($8000) has its most significant bit on. Loading this byte ($80)
49
Chapter Six
into the 6502 accumulator will set the minus flag on. The line
number of any program statement is less than or equal to
$7FFF. Loading the high order byte ($7F or less) of a program
line number into the accumulator will set the 6502 minus flag
off. This gives a simple test for a direct statement.
Initialization
Execution Control uses several parameters to help it manage
the task of statement execution.
STMCUR holds the address in the Statement Table of the
line currently being processed.
LLNGTH holds the length of the current line.
NXTSTD holds the displacement in the current line of the
next statement to process.
STMCUR already contains the correct value when
Execution Control begins processing. SETLN1 ($B81B) is called
to store the correct values into LLNGTH and NXTSTD.
Statement Execution
Since the user may have changed his or her mind about
execution, the routine checks to see if the user hit the break
key. If the user did hit BREAK, Execution Control carries out
XSTOP ($B793), the same routine that is executed when the
STOP statement is encountered. At the end of its execution,
the XSTOP routine gives control to the beginning of the editor.
If the user did not hit BREAK, Execution Control checks to
see whether we are at the end of the tokenized line. Since this
is the first statement in the line, we can't be at the end of the
line. So why do the test? Because this part of the routine is
executed once for each statement in the line in order to tell us
when we do reach the end of the line. (The end-of-line
procedure will be discussed later in this chapter.)
The statement length byte (the displacement to the next
statement in the line) is the first byte in a statement. (See
Chapter 3.) The displacement to this byte was saved in
NXTSTD. Execution Control now loads this new statement's
displacement using the value in NXTSTD.
The byte after the statement length in the line is the
statement name token. Execution Control loads the statement
name token into the A register. It saves the displacement to the
next byte, the first of the statement's tokens, in STINDEX for
the use of the statement simulation routines.
50
Chapter Six
The statement name token is used as an index to find this
statement's entry in the Statement Execution Table. Each table
entry consists of the address, minus 1, of the routine that will
simulate that statement. This simulation routine is called by
pushing the address from the table onto the 6502 CPU stack
and doing an RTS. Later, when a simulation routine is
finished, it can do an RTS and return to Execution Control.
(The name of most of the statement simulation routines in the
BASIC listing is the statement name preceded by an X: XFOR,
XRUN, XLIST.)
Most of the statement simulation routines return to
Execution Control after processing.
Execution Control again tests for BREAK and checks for the
end of the line. As long as we are not at end-of-line, it
continues to execute statements. When we reach end-of-line, it
does some end-of-line processing.
End-of-line Handling in a Direct Statement
When we come to the end of the line in a direct statement,
Execution Control has done its job and jumps to SNX3. The
READY message is printed and control goes back to the
Program Editor.
End-of-line Handling during Program Execution
Program execution is initiated when the user types RUN.
Execution Control handles RUN like any other direct
statement. The statement simulation routine for RUN initial-
izes STMCUR, NXTSTD, and LLNGTH to indicate the first
statement of the first line in the Statement Table, then returns
to Execution Control. Execution Control treats this first
program statement as the next statement to be executed,
picking up the statement name tokens and calling the
simulation routines.
Usually, Execution Control is unaware of whether it is
processing a direct statement or a program statement. End-of-
line is the only time the routine needs to make a distinction.
At the end of every program line, Execution Control gets
the length of the current line and calls GNXTL to update the
address in STMCUR to make the next line in the Statement
Table the new current line. Then it calls TENDST ($A9E2) to
test the new line number to see if it is another program line or a
direct statement. If it is a direct statement, we are at the end of
the user's program.
51
Chapter Six
Since the direct statement includes the RUN command that
started program execution, Execution Control does not execute
the line. Instead, Execution Control calls the same routine that
would have been called if the program had contained an END
statement (XEND, at $B78D). XEND does some end-of-
program processing, causes READY to be printed, and returns
to the beginning of the editor.
If we are not at the end of the user's program, processing
continues with the new current line.
Execution Control Subroutines
TENDST ($A9E2)
Exit parameters: The minus flag is set on if we are at the end of
program.
This routine checks for the end of the user's program in the
Statement Table.
The very last entry in the Statement Table is always a direct
statement. Whenever the statement indicated by STMCUR is
the direct statement, we have finished processing the user's
program.
The line number of a direct statement is $8000. The line
number of any other statement is $7FFF or less. TENDST
determines if the current statement is the direct statement by
loading the high-order byte of the line number into the A
register. This byte is at a displacement of one from the address
in STMCUR. If this byte is $80 (a direct statement), loading it
turns the 6502 minus flag on. Otherwise, the minus flag is
turned off.
GETSTMT ($A9A2)
Entry parameters: TSLNUM contains the line number of the
statement whose address is required.
Exit parameters: If the line number is found, the STMCUR
contains the address of the statement and the carry flag is set
off (clear). If the line number does not exist, STMCUR contains
the address where a statement with that line number should
be, and the carry flag is set on (set).
The purpose of this routine is to find the address of the
statement whose line number is contained in TSLNUM.
The routine saves the address currently in STMCUR into
SAVCUR and then sets STMCUR to indicate the top of the
52
Chapter Six
Statement Table. The line whose address is in STMCUR is
called the current line or statement.
GETSTMT then searches the Statement Table for the
statement whose line number is in TSLNUM. The line number
in TSLNUM is compared to the line number of the current line.
If they are equal, then the required statement has been found.
Its address is in STMCUR, so GETSTMT clears the 6502 carry
flag and is finished.
If TSLNUM is smaller than the current statement line
number, GETSTMT gets the length of the current statement by
executing GETLL ($A9DD). GNXTL ($A9D0) is executed to
make the next line in the statement table the current statement
by putting its address into STMCUR. GETSTMT then repeats
the comparison of TSLNUM and the line number of the current
line in the same manner.
If TSLNUM is greater than the current line number, then a
line with this line number does not exist. STMCUR already
points to where the line should be, the 6502 carry flag is already
set, and the routine is done.
GETLL ($A9DD)
Entry parameters: STMCUR indicates the line whose length is
desired.
Exit parameters: Register A contains the length of the
current line.
GETLL gets the length of the current line (that is, the line
whose address is in STMCUR).
The line length is at a displacement of two into the line.
GETLL loads the length into the A register and is done.
GNXTL ($A9D0)
Entry parameters: STMCUR contains the address of the current
line, and register A contains the length of the current line.
Exit parameters: STMCUR contains the address of the next
line.
This routine gets the next line in the statement table and
makes it the current line.
GNXTL adds the length of the current line (contained in
the A register) to the address of the current line in STMCUR.
This process yields the address of the next line in the statement
table, which replaces the value in STMCUR.
53
Chapter Six
SETLN1 ($B81B)
Entry parameters: STMCUR contains the address of the current
line.
Exit parameters: LLNGTH contains the length of the
current line. NXTSTD contains the displacement in the line to
the next statement to be executed (in this case, the first
statement in the line).
This routine initializes several line parameters so that
Execution Control can process the line.
The routine gets the length of the line, which is at a
displacement of two from the start of the line.
SETLN1 loads a value of three into the Y register to indicate
the displacement into the line of the first statement and stores
the value into NXTSTD as the displacement to the next
statement for execution.
SETLINE ($B818)
Entry parameters: TSLNUM contains the line number of a
statement.
Exit parameters: STMCUR contains the address of the
statement whose line number is in TSLNUM. LLNGTH
contains the length of the line. NXTSTD contains the
displacement in the line to the next statement to be executed (in
this case, the first statement in the line). Carry is set if the line
number does not exist.
This routine initializes several line parameters so that
execution control can process the line.
SETLINE first calls GETSTMT ($A9A2) to find the address
of the line whose number is in TSLNUM and put that address
into STMCUR. It then continues exactly like SETLN1.
54
Chapter Seven
Execute Expression
The Execute Expression routine is entered when the Program
Executor needs to evaluate a BASIC expression within a
statement. It is also the executor for the LET and implied LET
statements.
Expression operators have an order of precedence; some
must be simulated before others. To properly evaluate an
expression, Execute Expression rearranges it during the
evaluation.
Expression Rearrangement Concepts
Operator precedence rules in algebraic expressions are so
simple and so unconscious that most people aren't aware of
following them. When you evaluate a simple expression like
Y = AX 2 + BX + C, you don't think: "Exponentiation has a
higher precedence than multiplication, which has a higher
precedence than addition; therefore, I will first square the X,
then perform the multiplication." You just do it.
Computers don't develop habits or common sense — they
have to be specifically commanded. It would be nice if we could
just type Y = AX 2 + BX + C into our machine and have the
computer understand, but instead we must separate all our
variables with operators. We also have to learn a few new
operators, such as * for multiply and A for
exponentiation.
Given that we are willing to adjust our thinking this much,
we enter Y = A*X A 2 + B*X + C . The new form of expression
does not quite have the same feel as Y = AX 2 + BX + C; we have
translated normal human patterns halfway into a form the
computer can use.
Even the operation X A 2 causes another problem for the
computer. It would really prefer that we give it the two values
first, then tell it what to do with them. Since the computer still
needs separators between items, we should write X A 2 as
X,2,A.
Now we have something the computer can work with. It
can obtain the two values X,2, apply the operator A , and get a
result without having to look ahead.
55
Chapter Seven
If we were to transcribe X A 2*A in the same manner, we
would have X, 2, A , A, * . The value returned by X, 2, A is the first
value to multiply, so the value pair for multiplication is (X,2/\)
and A. Again we have two values followed by an operator, and
the computer can understand.
If we continue to transcribe the expression by pairing
values and operators, we find that we don't want to add the
value X A 2*A to B; we want to add the value X A 2* A to B*X.
Therefore, we need to tell the computer X,2, A ,A,*,B,X,*, + .
The value pair for the operator + is (X,2, A ,A,*) and (B,X,*).
The value pair for the final operation, =, is (X,2, A ,A,*,B,X,
*, + , C, + ) and Y. So the complete translation of Y = AX 2 + BX +
C is X,2, A ,A,*,B,X,*, + ,C, + ,Y, = .
Very few people other than Forth programmers put up
with this form of expression transcription. Therefore, Atari
BASIC was designed to perform this translation for us,
provided we use the correct symbols, like * and A .
The Expression Rearrangement Algorithm
The algorithm for expression rearrangement requires two LIFO
stacks for temporary storage of the rearranged terms. The
Operator Stack is used for temporarily saving operators; the
Argument Stack is used for saving arguments. Arguments are
values consisting of variables, constants, and the constant-like
values resulting from previous expression operations.
Operator Precedence Table
The Atari BASIC User's Manual lists the operators by
precedence. The highest-precedence operators, like <, >, and
= < , are at the top of the list; the lowest-precedence operator,
OR, is at the bottom. The operators at the top of the list get
executed before the operators at the bottom of the list.
The operators in the precedence table are arranged in the
same order as the Operator Name Table. Thus the token values
can be used as direct indices to obtain an operator precedence
value.
The entry for each operator in the Operator Precedence
Table contains two precedence values, the go-on to-stack
precedence and the come-off-stack precedence. When a new
operator has been plucked from an expression, its go-onto-
stack precedence is tested in relation to the top-of-stack
operator's come-off-stack precedence.
56
Chapter Seven
Expression Rearrangement Procedure
The symbols of the expression (the arguments and the
operators) are accessed sequentially from left to right, then
rearranged into their correct order of precedence by the
following procedure:
1. Initialize the Operator Stack with the Start Of Expression
(SOE) operator.
2. Get the next symbol from the expression.
3. If the symbol is an argument (variable or constant),
place the argument on the top of the Argument Stack.
Go to step 2.
4. If the symbol is an operator, save the operator in the
temporary save cell, SAVEOP.
5. Compare the go-onto-stack precedence of the operator
in SAVEOP to the come-off stack precedence of the
operator on the top of the Operator Stack.
6. If the top-of-stack operator's precedence is less than the
precedence of the SAVEOP operator, then the SAVEOP
operator is pushed onto the Operator Stack. When the
push is done, go back to step 2.
7. If the top-of-stack operator's precedence is equal to or
greater than the precedence of the SAVEOP operator,
then pop the top-of-stack operator and execute it. When
the execution is done, go back to step 5 and continue.
The Expression Rearrangement Procedure has one
apparent problem. It seems that there is no way to stop it.
There are no exits for the "evaluation done" condition. This
problem is handled by enclosing the expression with two
special operators: the Start Of Expression (SOE) operator, and
the End Of Expression (EOE) operator. Remember that SOE
was the first operator placed on the Operator Stack, in step 1.
Execution code for the SOE operator will cause the procedure
to be exited in step 7, when SOE is popped and executed. The
EOE operator is never executed. EOE's function is to force the
execution of SOE.
The precedence values of SOE and EOE are set to insure
that SOE is executed only when the expression evaluation is
finished. The SOE come-off-stack precedence is set so that its
value is always less than all the other operators' go-onto-stack
precedence values. The EOE go-onto-stack precedence is set so
that its value is always equal to or less than all the other
57
Chapter Seven
operators' (including SOE's) come-off-stack precedence
values.
Because SOE and EOE precedence are set this way, no
operator other than EOE can cause SOE to be popped and
executed. Second, EOE will cause all stacked operators,
including SOE, to be popped and executed. Since SOE is
always at the start of the expression and EOE is always at the
end of the expression, SOE will not be executed until the
expression is fully evaluated.
In actual practice, the SOE operator is not physically part of
the expression in the Statement Table. The Expression
Rearrangement Procedure initializes the Operator Stack with
the SOE operator before it begins to examine the expression.
There is no single operator defined as the End Of
Expression (EOE) operator. Every BASIC expression is
followed by a symbol like :, THEN, or the EOL character. All of
these symbols function as operators with precedence
equivalent to the precedence of our phantom EOE operator.
The THEN token, for example, serves a dual purpose. It not
only indicates the THEN action, but also acts as the EOE
operator when it follows an expression.
Expression Rearrangement Example
To illustrate how the expression evaluation procedure works,
including expression rearrangement, we will evaluate our
Y = A*X A 2 + B*X + C example and see how the expression is
rearranged to X,2, A ,A,*,B,X,*, + ,C, +,Y, = with a correct
result. To work our example, we need to establish a precedence
table for the operators. The values in Figure 7-1 are similar to
the actual values of these operators in Atari BASIC. The lowest
precedence value is zero; the highest precedence value is $0F.
Figure 7-1. Example Precedence Table
operator
go-on-stack
come-off-stac
symbol
precedence
precedence
SOE
NA
$00
+
$09
$09
*
$0A
$0A
A
$0C
$0C
=
$0F
$01
! (EOE)
$00
NA
58
Chapter Seven
Symbol values and notations. In the example steps, the
term PSn refers to step n in the Expression Rearrangement
Procedure (page 57). Step 5, for instance, will be called PS5.
In the actual expression, the current symbol will be
underlined. If B is the current symbol, then the actual
expression will appear as Y = A*X 2 + B*X + C . In the
rearranged expression, the symbols which have been evaluated
up to that point will also be underlined.
The values of the variables are:
A = 2 C=6
B=4 X=3
The variable values are assumed to be accessed when the
variable arguments are popped for operator execution.
The end-of-expression operator is represented by ! .
Example step 1.
Actual Expression: Y = A*XA2 + B*X + C!
Rearranged Expression: X,2, A , A, *,B,X, *, + ,C, + , Y, = , !
Argument Stack:
Operator Stack: SOE
SAVEOP:
PS1 has been executed. The Operator Stack has been
initialized with the SOE operator. We are ready to start
processing the expression symbols.
Example step 2.
Actual Expression: Y = A*XA2 + B*X + C!
Rearranged Expression: X,2,A ,A,*,B,X,*, + ,C, + ,Y, =,!
Argument Stack: Y
Operator Stack: SOE
SAVEOP:
The first symbol, Y, has been obtained and stacked in the
Argument Stack according to PS2 and PS3.
Example step 3.
Actual Expression: Y_=A*XA 2 + B*X + C!
Rearranged Expression: X,2,A ,A,*,B,X,*, + ,C, +,Y, =,!
Argument Stack: Y
Operator Stack: SOE, =
SAVEOP: =
59
Chapter Seven
Operator = has been obtained via PS2. The relative
precedences of SOE ($00) and = ($0F) dictate that the = be
placed on the Operator Stack via PS6.
Example step 4.
Actual Expression: Y=A*XA2 + B*X + C!
Rearranged Expression: X,2, A ,A,*,B,X,*, +,C, + ,Y, =,!
Argument Stack: Y,A
Operator Stack: SOE, =
SAVEOP:
The next symbol is A. This symbol is pushed onto the
Argument Stack via PS3.
Example step 5.
Actual Expression: Y = A*XA 2 + B*X + C!
Rearranged Expression: X,2, A ,A,*,B,X,*, + ,C, + ,Y, = ,!
Argument Stack: Y,A
Operator Stack: SOE, = , *
SAVEOP: *
The next symbol is the operator *. The relative precedence
of * and = dictates that * be pushed onto the Operator Stack.
Example step 6.
Actual Expression: Y = A*XA2 + B*X + C!
Rearranged Expression: X,2,A ,A,*,B,X,*, + ,C, + ,Y, =,!
Argument Stack: Y,A,X
Operator Stack: SOE, = ,*
SAVEOP:
The next symbol is the variable X. This symbol is stacked
on the Argument Stack according to PS3.
Example step 7.
Actual Expression: Y = A*XA 2 + B*X + C!
Rearranged Expression: X,2, A ,A,*,B,X,*, +,C, + ,Y, = ,!
Argument Stack: Y,A,X
Operator Stack: SOE,=,*,A
SAVEOP: A
The next symbol is A . The relative precedence of the
and the * dictate that A be stacked via PS6.
60
Chapter Seven
Example step 8.
Actual Expression: Y = A*XA 2_+B*X + C!
Rearranged Expression: X,2, a , A, *,B,X, *, + ,C, + , Y, = , !
Argument Stack : Y, A, X, 2
Operator Stack: SOE, = ,*,a
SAVEOP:
The next symbol is 2. This symbol is stacked on the
Argument Stack via PS3.
Example step 9.
Actual Expression: Y = A*XA 2 + B*X + C!
Rearranged Expression: X,2,A, A, *,B,X, *, + ,C, + , Y, = , !
Argument Stack: Y,A,9
Operator Stack : SOE, = , *
SAVEOP: +
The next symbol is the operator + . The precedence of the
operator that was at the top of the stack, a t [ s greater than the
precedence of + . PS7 dictates that the top-of-stack operator be
popped and executed.
The a operator is popped. Its execution causes arguments
X and 2 to be popped from the Argument Stack, replacing the
variable with the value that it represents and operating on the
two values yielded: X A 2 = 3 a 2 = 9. The resulting value, 9, is
pushed onto the Argument Stack. The + operator remains in
SAVEOP. We continue at PS5.
Note that in the rearranged expression the first symbols,
X,2, A , have been evaluated according to plan.
Example step 10.
Actual Expression: Y = A*XA 2 + B*X + C!
Rearranged Expression: X,2,A,A,*, B,X,*, +,C, + ,Y, = ,!
Argument Stack: Y,18
Operator Stack: SOE, =
SAVEOP: +
This step originates at PS5. The SAVEOP operator, +, has
a precedence that is less than the operator which was at the top
of the stack, *. Therefore, according to PS7, the * is popped
and executed.
The execution of * results in A*9 = 2*9 = 18. The resulting
value is pushed onto the Argument Stack.
61
Chapter Seven
Example step 11.
Actual Expression: Y = A*XA2 + B*X + C!
Rearranged Expression: X,2,A,A,*,B,X,*, + ,C, + ,Y, = ,!
Argument Stack: Y,18
Operator Stack: SOE, = ,+
SAVEOP:
When step 10 finished, we went to PS5. The operator in
SAVEOP was + . Since + has a higher precedence than the top-
of-stack operator, =, the + operator was pushed onto the
Operator Stack via PS6.
Example step 12.
Actual Expression: Y = A*XA2 + B*X + C!
Rearranged Expression: X,2,A,A,*,B,X,*, +,C, +,Y, = ,!
Argument Stack: Y,18,B
Operator Stack: SOE, = , +
SAVEOP:
The next symbol is the variable B, which is pushed onto the
Argument Stack via PS3.
Example step 13.
Actual Expression: Y = A*XA 2 + B*X + C!
Rearranged Expression: X,2,A,A,*, B,X,*, +,C, +,Y, = ,!
Argument Stack: Y,18,B
Operator Stack: SOE, = , + ,*
SAVEOP: *
The next symbol is the operator *. Since * has a higher
precedence than the top-of-stack +, * is pushed onto the stack
viaPS6.
Example step 14.
Actual Expression: Y = A*X a 2 + B*X + C!
Rearranged Expression: X,2,A,A,*,B ,X,*, +,C, +,Y, = ,!
Argument Stack: Y,18,B,X
Operator Stack: SOE, = , + ,*
SAVEOP:
The variable X is pushed onto the Argument Stack via PS3.
Example step 15.
Actual Expression: Y = A*XA 2 + B*X+C!
Rearranged Expression: X,2,A,A,*,B,X,*, + ,C, +,Y, = ,!
62
Chapter Seven
Argument Stack: Y,18,12
Operator Stack: SOE, =,+
SAVEOP: +
The operator + is retrieved from the expression. Since +
has a lower precedence than * which is at the top of the stack,
* is popped and executed.
The execution of * causes B*X = 4*3 = 12. The resulting
value of 12 is pushed onto the Argument Stack. We will
continue at PS5 via the PS7 exit rule.
Example step 16.
Actual Expression: Y = A*XA 2 + B*X + C!
Rearranged Expression: X,2,A,A,*,B,X,*, + , C, + ,Y, = ,!
Argument Stack: Y,30
Operator Stack: SOE, =
SAVEOP: +
This step starts at PS5. The SAVEOP operator, +, has
precedence that is equal to the precedence of the top-of-stack
operator, also + . Therefore, + is popped from the operator
stack and executed. The results of the execution cause 18 + 12,
or 30, to be pushed onto the Argument Stack. PS5 is called.
Example step 17.
Actual Expression: Y = A*XA2 + B*X + C!
Rearranged Expression: X,2,A,A,*,B,X,*, + , C, +,Y, =,!
Argument Stack: Y,30
Operator Stack: SOE, = , +
SAVEOP:
This step starts at PS5. The SAVEOP is + . The top-of-stack
operator, =, has a lower precedence than +; therefore, + is
pushed onto the stack via PS6.
Example step 18.
Actual Expression: Y = A*XA 2 + B*X + C!
Rearranged Expression: X,2,A,A,*,B,X,*, + , C, + ,Y, = ,!
Argument Stack: Y,30,C
Operator Stack: SOE, = , +
SAVEOP:
The variable C is pushed onto the Argument Stack via PS3.
63
Chapter Seven
Example step 19.
Actual Expression: Y=A*XA2+B*X + C!
Rearranged Expression: X,2, A ,A,*,B,X,*, + ,C, + , Y, = , !
Argument Stack: Y,36
Operator Stack: SOE, =
SAVEOP: !
The EOE operator ! is plucked from the expression. The
EOE has a lower precedence than the top-of-stack + operator.
Therefore, + is popped and executed. The resulting value of
30 + 6, 36, is pushed onto the Argument Stack. PS5 will execute
next.
Example step 20.
Actual Expression: Y=A*XA 2+B*X + C[
Rearranged Expression: X,2, A /A,*,B,X,*, + ,C, + ,Y, =, !
Argument Stack:
Operator Stack: SOE
SAVEOP: !
This step starts at PS5. The ! operator has a lower
precedence than the top-of-stack = operator, which is popped
and executed. The execution of = causes the value 36 to be
assigned to Y. This leaves the Argument Stack empty. PS5 will
be executed next.
Example step 21.
Actual Expression: Y = A*XA 2 + B*X + C|
Rearranged Expression: X,2,A,A,*,B,X,*, + ,C, + ,Y, = ,!
Argument Stack:
Operator Stack:
SAVEOP: !
The ! operator in SAVEOP causes the SOE operator to be
popped and executed. The execution of SOE terminates the
expression evaluation.
Note that the rearranged expression was executed exactly
as predicted.
Mainline Code
The Execute Expression code implements the Expression
Rearrangement Procedure. The mainline code starts at the
EXEXPR label at $AAE0. The input to EXEXPR starts at the
current token in the current statement. STMCUR points to the
64
Chapter Seven
current statement. STINDEX contains the displacement to the
current token in the STMCUR statement. The output of
EXEXPR is whatever values remain on the top of the argument
stack when the expression evaluation is finished.
In the following discussion, PSn refers to the procedure
step n in the Expression Rearrangement Procedure.
PS1, initialization, occurs when EXEXPR is entered.
EXPINT is called to initialize the operator and argument stacks.
EXPINT places the SOE operator on the operator stack.
PS2, which obtains the next token, directly follows
initialization at EXNXT ($AAE3). The code calls EGTOKEN to
get the next expression symbol and classify it. If the token is an
argument, the carry will be set. If the token is an operator, the
carry will be clear.
If the token is an argument, PS3 is implemented via a call to
ARGPUSH. After the argument is pushed onto the argument
stack, EXNXT (PS2) will receive control.
If the token was an operator, then the code at EXOT
($AAEE) will be executed. This code implements PS4 by saving
the token in EXSVOP.
PS5, which compares the precedents of the EXSVOP token
and the top-of-stack token, follows EXOT at EXPTST ($AAFA).
This code also executes the SOE operator. If SOE is popped,
then Execute Expression finishes via RTS.
If the top-of-stack operator precedence is less than the
EXSVOP operator precedence, PS6 is implemented at
EOPUSH ($AB15). EOPUSH pushes EXSVOP onto the
operator stack and then goes to EXNXT (PS2).
If the top-of-stack operator precedence is greater than or
equal to the EXSVOP operator precedence, then PS7 is
implemented at EXOPOP ($AB0B). EXOPOP will pop the top-
of-stack operator and execute it by calling EXOP. When EXOP
is done, control passes to EXPTST (PS5).
Expression Evaluation Stacks
The two expression evaluation stacks, the Argument Stack and
the Operator Stack, share a single 256-byte memory area. The
Argument Stack grows upward from the lower end of the 256-
byte area. The Operator Stack grows downward front the
upper end of the 256-byte area.
The 256-byte stack area is the multipurpose buffer at the
start of the RAM tables. The buffer is pointed to by the
65
Chapter Seven
ARGSTK (also ARGOPS) zero-page pointer at $80. The current
index into the Argument Stack is maintained by ARSLVL
($AA). When the Argument Stack is empty, ARSLVL is zero.
The OPSTKX cell maintains the current index into the
Operator Stack. When the Operator Stack is initialized with the
SOE operator, OPSTKX is initialized to $FF. As operators are
added to the Operator Stack, OPSTKX is decremented. As
arguments are added to the Argument Stack, ARSLVL is
incremented.
Since the two stacks share a single 256-byte memory area,
there is a possibility that the stacks will run into each other. The
code at $ABC1 is used to detect a stack collision. It does this by
comparing the values in ARSLVL and OPSTKX. If ARSLVL is
greater than or equal to OPSTKX, then a stack collision occurs,
sending the STACK OVERFLOW error to the user.
Operator Stack
Each entry on the Operator Stack is a single-byte operator-type
token. Operators are pushed onto the stack at EXOPUSH
($AB15) and are popped from the stack at EXOPOP ($AB0B).
Argument Stack
Each entry on the Argument Stack is eight bytes long. The
format of these entries is described in Figures 7-2, 7-3, and 7-4,
and are the same as the formats for entries in the Variable Value
Table.
Unlike the Variable Value Table, the Argument Stack must
deal with both variables and constants. In Figure 7-2, we see
that VNUM is used to distinguish variable entries from
constant entries.
The SADR and AADR fields in the entries for strings and
arrays are of special interest. (See Figures 7-3 and 7-4.) When a
string or array variable is dimensioned, space for the variable is
created in the string/array space. The displacement to the start
of the variable's area within the string/array space is placed in
the SADR/ AADR fields at that time. A displacement is used
rather than an absolute address because the absolute address
can change if any program changes are made after the DIM
statement is executed.
Execute Expression needs these values to be absolute
address values within the 6502 address space. When a
string/array variable is retrieved from the Variable Value Table,
66
Chapter Seven
the displacement is transformed to an absolute address. When
(and if) the variable is put back into the Variable Value Table,
the absolute address is converted back to a displacement.
The entries for string constants also deserve some special
attention. String constants are the quoted strings within the
user program. These strings become part of the tokenized
statements in the Statement Table. When Execute Expression
gets a string token, it will create a string constant Argument
Stack entry. This entry's SADR is an absolute address pointer
to the string in the Statement Table. SLEN and SDIM are set to
the actual length of the quoted string.
Argument Work Area
An argument which is currently being examined by Execute
Expression is kept in a special zero-page Argument Work Area
(AWA). The AW A starts at the label VTYPE at $D2.
Figure 7-2. Argument Stack Entry
1 2
VTYPE
VNUM
DATA
■*• Data Field. Format depends on VTYPE.
If VNUM = 0, the entry is a constant.
If VNUM > 0, the entry is a variable. In this case,
the VNUM value is the entry number in the Variable
Value Table. The token representing this variable is
VNUM + $80.
- $00 = Data is a six-byte floating point constant.
$80 = Data represents an undimensioned string.
$81 = Data represents a dimensioned string with
a relative address pointer.
$83 = Data represents a dimensioned string with
an absolute address pointer.
$40 = Data represents an undimensioned array.
$41 = Data represents a dimensioned array with
a relative address pointer.
u $43 = Data represents a dimensioned array with
an absolute address pointer.
67
Chapter Seven
Figure 7-3. Argument Stack String Entry
VTYPE
VNUM
SADR
SLEN
SDIM
J
\_^jr Dimensioned length of the string. Valid only if
L VTYPE = $81 or $83.
i-Current length of the string. Valid only if VTYPE
*T- =<R81 or <R83
= $81 or $83.
p String address. Valid only if VTYPE = $81 or $83.
If VTYPE = $81, then SADR is the displacement
of the start of the string from the start of the
string/array space.
If VTYPE = $83, then SADR is the absolute address
L of the start of the string.
Figure 7-4. Argument Stack Array Entry
VTYPE VNUM AADR
DIM1
DIM2
J
- When an array has been dimensioned as A(D1,D2),
this field contains the D2 value. If an array
was dimensioned as A(D1), then this field is
zero. The field is valid only if VTYPE = $41 or
u $43.
■ When an array has been dimensioned, as A(D1,D2)
or as A(D1), this field contains the Dl value.
■ The field is valid only if VTYPE = $41 or $43.
■ Array Address. Valid only if VTYPE = $41 or $43.
If VTYPE = $41, the AADR is the displacement to
the start of the array in the string/array space.
If VTYPE = $43, the AADR is the absolute address
L of the start of the string.
68
Chapter Seven
Operator Executions
An operator is executed when it is popped from the Operator
Stack. Execute Expression calls EXOP at $AB20 to start this
execution. The EXOP routine uses the operator token value as
an index into the Operator Execution Table ($AA70). The
operator execution address from this table, minus 1, is placed
on the 6502 CPU stack. An RTS is then executed to begin
executing the operator's code.
The names of the operator execution routines all begin with
the characters XP.
All the Atari BASIC functions, such as PEEK, RND, and
ABS, are executed as operators.
Most routines for the execution of the operators are very
simple and straightforward. For example, the * operator
routine, XPMUL ($AC96), pops two arguments, multiplies
them via the floating point package, pushes the result onto the
argument stack, and returns.
String, Array, DIM, and Function Operations
Any array reference in an expression may be found in one of
two forms: A(x) or A(x,y). The indices x and y may be any
valid expression. The intent of the indices is to reference a
specific array element.
Before the specific element reference can take place, the x
and/or y index expressions must be fully evaluated. To do this,
the characters '(' ',' and ')' are made operators. The
precedence of these operators forces things to happen in the
correct sequence. Figure 7-5 shows the relative precedence of
these operators for an array.
Figure 7-5. Array Operator Precedence
come-off-stack
precedence
$02
$03
$0E
As a result of these precedence values, ( has a high
enough precedence to go onto the stack, no matter what other
operator is on the top of the stack.
69
operator
symbol
go-on-stack
precedence
(
, (comma)
)
$0F
$04
$04
Chapter Seven
The comma's goon-stack precedence will force all operators
except ( to be popped and executed. As a result, the x index
sub-expression, in the expression A(.v,i/), will be fully evaluated
and the final x index value will be pushed onto the Argument
Stack.
The comma will then be placed onto the Operator Stack. Its
come-off-stack precedence is such that no other operator,
except ) , will pop it off.
The ) operator precedence will force any 1/ index
expression to be fully evaluated and the y index result value to
be placed onto the Argument Stack.
It will then force the comma operator to be popped and
executed. This action results in a comma counter being
incremented.
The ) will then force the ( to be popped and executed.
The execution of ( results in the proper array element being
referenced. The ( operator will pop the indices from the
Argument Stack. The number of indices (either zero or one) to
be popped is governed by the comma counter, which was
incremented by one for each comma that was popped and
executed.
Atari BASIC has numerous ( tokens, and each causes a
different ( routine to be executed. These ( operators are array
(CALPRN), string (CSLPRN), array DIM (CDLPRN), string DIM
(CDSLPR), function (CFLPRN), and the expression grouping
CLPRN operator. The Syntax Table pseudo-instruction CHNG
is used to change the CLPRN token to the other ( tokens in
accordance with the context of the grammar.
The expression operations for each of these various (
operators in relation to commas and ( is exactly the same.
When ( is executed, the comma count will show how many
arguments the operator's code must pop from the argument
stack. Each of these arguments will have been evaluated down
to a single value in the form of a constant.
70
Chapter Eight
Execution Boundary
Conditions
BASIC Language statements can be divided into groups with
related functions. The execution boundary statements, RUN,
STOP, CONT and END, cause a BASIC program to start or
stop executing. The routines which simulate these statements
are XRUN, XSTOP, XCONT, and XEND.
Program Termination Routines
Any BASIC statement can be used as either a direct statement
or a program statement, but some only make sense in one
mode. The STOP statement has no real meaning when entered
as a direct statement. When the statement simulation routine
for STOP is asked to execute in direct mode, it does as little
processing as possible and exits. Useful processing occurs only
when STOP is a program statement.
STOP ($B7A7). The XSTOP and XEND routines are similar and
perform some of the same tasks. The tasks common to both are
handled by the STOP routine.
If this statement is not a direct statement, the STOP routine
saves the line number of the current line in STOPLN. This line
number is used later for printing the STOPed message. It is
also used by the CONT simulation routine (XCONT) to
determine where to restart program execution. (Since XEND
also uses this routine, it is possible to CONTinue after an END
statement in the middle of a program.)
The STOP routine also resets the LIST and ENTER devices
to the screen and the keyboard.
XSTOP ($B793). XSTOP does the common STOP processing
and then calls :LPRTOKEN($B535) to print the STOPed
message. It then calls one of the error printing routines,
:ERRM2 ($B974), to output the AT LINE nnn portion. The
:ERRM2 routine will not print anything if this was a direct
statement. When :ERRM2 is finished, it jumps back to the start
of the editor.
71
Chapter Eight
XEND ($B78D). XEND calls the STOP routine to save the
current line number. It then transfers to the start of the editor
via the SNX1 entry point. This turns off the sound, closes any
open IOCBs, and prints the READY message. XEND also
leaves values on the 6502 CPU stack. These values are thrown
away when the editor resets the stack.
END OF PROGRAM. A user may have neglected to include an
END statement in his program. In this case, when Execution
Control comes to the end of the Statement Table it calls XEND,
and the program is terminated exactly as if the last statement in
the program were an END.
Program Initiation Routines
The statements that cause a user's program to begin execution
are RUN and CONT. These statements are simulated by XRUN
and XCONT.
XCONT ($B7BE). The CONT statement has no meaning when
encountered as a program statement, so its execution has no
effect.
When the user enters CONT as a direct statement, XCONT
uses the line number that was saved in STOPLN to set
Execution Control's line parameters (STMCUR, NXTSTD,
and LLNGTH). This results in the current line being the line
following the one whose line number is in STOPLN. This
means that any statement following STOP or END on a line
will not be executed; therefore, STOP and END should always
be the last statement in the line.
If we are at the end of the Statement Table, XCONT
terminates as if an END statement had been encountered in the
program. If there are more lines to process, XCONT returns to
Execution Control, which resumes processing at the line whose
address was just put into STMCUR.
XRUN ($B74D). The RUN statement comes in two formats,
RUN and RUN < filespec > . In the case of RUN < filespec > ,
XRUN executes XLOAD to load a saved program, which
replaces the current one in memory. The process then proceeds
like RUN.
XRUN sets up Execution Control's line pointers to indicate
the first line in the Statement Table. It clears some flags used to
control various other BASIC statements; for example, it resets
STOPLN to 0. It closes all IOCBs and executes XCLR to reset all
72
Chapter Eight
the variables to zero and get rid of any entries in the
String/ Array Table or the Runtime Stack.
If there is no program, so the only thing in the Statement
Table is the direct statement, then XRUN does some clean-up,
prints READY, and returns to the start of the editor, which
resets the 6502 CPU stack.
If there is a program, XRUN returns to Execution Control,
which starts processing the first statement in the table as the
current statement.
When RUN < filespec > is used as a program statement, it
performs the useful function of chaining to a new program, but
if RUN alone is used as a program statement, an infinite loop
will probably result.
Error Handling Routine
There are other conditions besides the execution boundary
statements that terminate a program's execution. The most
familiar are errors.
There are two kinds of errors that can occur during
execution: Input/Output errors and BASIC language errors.
Any BASIC routine that does I/O calls the IOTEST routine
($BCB3) to check the outcome of the operation. If an error that
needs to be reported to the user is indicated, IOTEST gets the
error number that was returned by the Operating System and
joins the Error Handling Routine, ERROR ($B940), which
finishes processing the error.
When a BASIC language error occurs, the error number is
generated by the Error Handling Routine. This routine
calculates the error by having an entry point for every BASIC
language error. At each entry point, there is a 6502 instruction
that increments the error number. By the time the main
routine, ERROR, is reached, the error number has been
generated.
The Error Handling Routine calls STOP ($B7A7) to save the
line number of the line causing the error in STOPLN. It tests
TRAPLN to see if errors are being TRAPed. The TRAP option is
on if TRAPLN contains a valid line number. In this case, the
Error Handler does some clean-up and joins XGOTO, which
transfers processing to the desired line.
If the high-order byte of the line number is $80 (not a valid
line number), then we are not TRAPing errors. In this case, the
Error Handler prints the four-part error message, which
73
Chapter Eight
consists of ERROR, the error number, AT LINE, and finally the
line number. If the line in error was a direct statement, the AT
LINE part is not printed. The error handler resets ERRNUM to
zero and is finished.
The Error Handling Routine does not do an orderly return,
but jumps back to the start of the editor at the SYNTAX entry
point where the 6502 stack is reset, clearing it of the now-
unwanted return addresses.
74
Chapter Nine
Program Flow
Control Statements
Execution Control always processes the statement in the
Statement Table that follows the one it thinks it has just
finished. This means that statements in a BASIC program are
usually processed in sequential order.
Several statements, however, can change that order:
GOTO, IF, TRAP, FOR, NEXT, GOSUB, RETURN, POP, and
ON. They trick Execution Control by changing the parameters
that it maintains.
Simple Flow Control Statements
XGOTO ($B6A3)
The simplest form of flow control transfer is the GOTO
statement, simulated by the XGOTO routine.
Following the GOTO token in the tokenized line is an
expression representing the line number of the statement that
the user wishes to execute next. The first thing the XGOTO
routine does is ask Execute Expression to evaluate the
expression and convert it to a positive integer. XGOTO then
calls the GETSTMT routine to find this line number in the
Statement Table and change Execution Control's line
parameters to indicate this line.
If the line number does not exist, XGOTO restores the line
parameters to indicate the line containing the original GOTO,
and transfers to the Error Handling Routine via the ERNOLN
entry point. The Error Handling Routine processes the error
and jumps to the start of the editor.
If the line number was found, XGOTO jumps to the
beginning of Execution Control (EXECNL) rather than
returning to the point in the routine from which it was called.
This leaves garbage on the 6502 CPU stack, so XGOTO first
pulls the return address off the stack.
75
Chapter Nine
X1F ($B778)
The IF statement changes the statement flow based on a
condition. The simulation routine, XIF, begins by calling a
subroutine of Execute Expression to evaluate the condition.
Since this is a logical (rather than an arithmetic) operation, we
are only interested in whether the value is zero or non-zero. If
the expression was false (non-zero), XIF modifies Execution
Control's line parameters to indicate the end of this line and
then returns. Execution Control moves to the next line,
skipping any remaining statements on the original IF statement
line.
If the expression is true (zero), things get a little more
complicated. Back during syntaxing, when a statement of the
form IF < expression > THEN < statement > was encountered,
the pre-compiler generated an end-of-statement token after
THEN. XIF now tests for this token. If we are at the end of the
statement, XIF returns to Execution Control, which processes
what it thinks is the next statement in the current line, but
which is actually the THEN < statement > part of the IF
statement.
If XIF does not find the end-of-statement token, then the
statement must have had the form IF < expression > THEN
< line number > . XIF jumps to XGOTO, which finishes
processing by changing Execution Control's line parameters to
indicate the new line.
XTRAP ($B7E1)
The TRAP statement does not actually change the program
flow when it is executed. Instead, the XTRAP simulation
routine calls a subroutine of Execute Expression to evaluate the
line number and then saves the result in TRAPLN ($BC).
The program flow is changed only if there is an error. The
Error Handling Routine checks TRAPLN. If it contains a valid
line number, the error routine does some initial set-up and
joins the XGOTO routine to transfer to the new line.
Runtime Stack Routines
The rest of the Program Flow Control Statements use the
Runtime Stack. They put items on the stack, inspect them,
and/or remove them from the stack.
Every item on the Runtime Stack contains a four-byte
header. This header consists of a one-byte type indication, a
76
Chapter Nine
two-byte line number, and a one-byte displacement to the
Statement Name Token. (See pages 18-19.) The type byte is the
last byte placed on the stack for each entry. This means that the
pointer to the top of the Runtime Stack (RUNSTK) points to the
type byte of the most recent entry on the stack. A zero type
byte indicates a GOSUB-type entry. Any non-zero type byte
represents a FOR-type entry.
A GOSUB entry consists solely of the four-byte header. A
FOR entry contains twelve additional bytes: a six-byte limit
value and a six-byte step value.
Several routines are used by more than one of the
statement simulation routines.
PSHRSTK ($B683) This routine expands the Runtime Stack
by calling EXPLOW and then storing the type byte, line
number, and displacement of the Statement Name Token on
the stack.
POPRSTK ($B841) This routine makes sure there really is
an entry on the Runtime Stack. POPRSTK saves the
displacement to the statement name token in SVDISP, saves
the line number in TSLNUM, and puts the type/variable
number in the 6502 accumulator. It then removes the entry by
calling the CONTLOW routine.
:GETTOK ($B737) This routine first sets up Execution
Control's line parameters to point to the line whose number is
in the entry just pulled from the Runtime Stack. If the line was
found, :GETTOK updates the line parameters to indicate that
the statement causing this entry is now the current statement.
Finally, it loads the 6502 accumulator with the statement name
token from the statement that created this entry and returns to
its caller.
If the line number does not exist, :GETTOK restores the
current statement address and exits via the ERGFDEL entry
point in the Error Handling Routine.
Now let's look at the simulation routines for the statements
that utilize the Runtime Stack.
XFOR ($B64B)
XFOR is the name of the simulation routine which executes a
FOR statement.
In the statement FOR I = 1 TO 10 STEP 2:
/ is the loop control variable
77
Chapter Nine
1 is its initial value
10 is the limit value
2 is the step value
XFOR calls Execute Expression, which evaluates the initial
value and puts it in the loop control variable's entry in the
Variable Value Table.
Then it calls a routine to remove any currently unwanted
stack entries — for example, a previous FOR statement that
used the same loop control variable as this one.
XFOR calls a subroutine of Execute Expression to evaluate
the limit and step values. If no step value was given, a value of
1 is assigned. It expands the Runtime Stack using EXPLOW
and puts the values on the stack.
XFOR uses PSHRSTK to put the header entry on the stack.
It uses the variable number of the loop control variable
(machine-language ORed with $80) as the type byte. XFOR
now returns to Execution Control, which processes the
statement following the FOR statement.
The FOR statement does not change program flow. It just
sets up an entry on the Runtime Stack so that the NEXT
statement can change the flow.
XNEXT ($B6CF)
The XNEXT routine decides whether to alter the program flow,
depending on the top Runtime Stack entry. XNEXT calls the
POPRSTK routine repeatedly to remove four-byte header
entries from the top of the stack until an entry is found whose
variable number (type) matches the NEXT statement's variable
token. If the top-of-stack or GOSUB-type entry is encountered,
XNEXT transfers control to an Error Handling Routine via the
ERNOFOR entry point.
To compute the new value of the loop variable, XNEXT
calls a subroutine of Execute Expression to retrieve the loop
control variable's current value from the Variable Value Table,
then gets the step value from the Runtime Stack, and finally
adds the step value to the variable value. XNEXT again calls an
Execute Expression subroutine to update the variable's value in
the Variable Value Table.
XNEXT gets the limit value from the stack to determine if
the variable's value is at or past the limit. If so, XNEXT returns
to Execution Control without changing the program flow, and
the next sequential statement is processed.
78
Chapter Nine
If the variable's value has not reached the limit, XNEXT
returns the entry to the Runtime Stack and changes the
program flow. POPRSTK already saved the line number of the
FOR statement in TSLNUM and the displacement to the
statement name token in SVDISP. XNEXT calls the :GETTOK
routine to indicate the FOR statement as the current statement.
If the token at the saved displacement is not a FOR
statement name token, then the Error Handling Routine is
given control at the ERGFDEL entry point. Otherwise, XNEXT
returns to Execution Control, which starts processing with the
statement following the FOR statement.
XGOSUB ($B6A0)
The GOSUB statement causes an entry to be made on the
Runtime Stack and also changes program flow.
The XGOSUB routine puts the GOSUB-type indicator
(zero) into the 6502 accumulator and calls PSHRSTK to put a
four-byte header entry on the Runtime Stack for later use by
the simulation routine for RETURN. XGOSUB then processes
exactly like XGOTO.
XRTN ($B719)
The RETURN statement causes an entry to be removed from
the Runtime Stack. The XRTN routine uses the information in
this entry to determine what statement should be processed
next.
The XRTN first calls POPRSTK to remove a GOSUB-type
entry from the Runtime Stack. If there are no GOSUB entries
on the stack, then the Error Handling Routine is called at
ERBRTN. Otherwise, XRTN calls :GETTOK to indicate that the
statement which created the Runtime Stack entry is now the
current statement.
If the statement name token at the saved displacement is
not the correct type, then XRTN exits via the Error Handling
Routine's ERGFDEL entry point. Otherwise, control is
returned to the caller. When Execution Control was the caller,
then GOSUB must have created the stack entry, and
processing will start at the statement following the GOSUB.
Several other statements put a GOSUB-type entry on the
stack when they need to mark their place in the program. They
do not affect program flow and will be discussed in later
chapters.
79
Chapter Nine
XPOP ($B841)
The XPOP routine uses POPRSTK to remove an entry from the
Runtime Stack. A user might want to do this if he decided not
to RETURN from a GOSUB.
XON ($B7ED)
The ON statement comes in two versions: ON-GOTO and ON-
GOSUB. Only ON-GOSUB uses the Runtime Stack.
The XON routine evaluates the variable and converts it to
an integer (MOD 256). If the value is zero, XON returns to
Execution Control without changing the program flow.
If the value is non-zero and this is an ON-GOSUB
statement, XON puts a GOSUB-type entry on the Runtime
Stack for RETURN to use later.
From this point, ON-GOSUB and ON-GOTO perform in
exactly the same manner. XON uses the integer value
calculated earlier to index into the tokenized statement line to
the correct GOTO or GOSUB line number. If there is no line
number corresponding to the index, XON returns to Execution
Control without changing program flow. Otherwise, XON
joins XGOTO to finish processing.
80
Chapter Ten
Tokenized Program
Save and Load
The tokenized program can be saved to and reloaded from a
peripheral device, such as a disk or a cassette. The primary
statement for saving the tokenized program is SAVE. The
saved program is reloaded into RAM with the LOAD
statement. The CSAVE and the CLOAD statements are special
versions of SAVE and LOAD for use with a cassette.
Saved File Format
The tokenized program is completely contained within the
Variable Name Table, the Variable Value Table, and the
Statement Table. However, since these tables vary in size, we
must also save some information about the size of the tables.
The SAVE file format is shown in Figure 10-1. The first part
consists of seven fields, each of them two bytes long, which tell
where each table starts or ends. Part two contains the saved
program's Variable Name Table (VNT), Variable Value Table
(WT), and Statement Table (ST).
The displacement value in all the part-one fields is actually
the displacement plus 256. We must subtract 256 from each
displacement value to obtain the true displacement.
The VNT starts at relative byte zero in the file's second
part. The second field in part one holds that value plus 256.
The DWT field in part one contains the displacement,
minus 256, of the VVT from the start of part two.
The DST value, minus 256, gives the displacement of the
Statement Table from the start of part two.
The DEND value, minus 256, gives the end-of-file
displacement from the start of part two.
81
Chapter Ten
Figure 10-1. SAVE File Format
PARTI
2
4
6
8
10
12
14
256
Not Used.
DVVT
DST
Not Used.
DEND
PART 2
r-256
r-256
)-256
VNT
DVV"
VVT
DSN'
ST
DENI
The displacement of the VNT from
the beginning of part two, plus 256.
The displacement of VVT from the
' beginning of part two, plus 256.
> The displacement of the ST from the
beginning of part two, plus 256.
The displacement of the end of the
file from the beginning of part two.
i Variable Name Table
Variable Value Table
Statement Table
XSAVE ($BB5D)
The code that implements the SAVE statement starts at the
XSAVE ($BB5D) label. Its first task is to open the specified
output file, which it does by calling ELADVC.
The next operation is to move the first seven RAM table
pointers from $80 to a temporary area at $500. While these
pointers are being moved, the value contained in the first
pointer is subtracted from the value in each of the seven
pointers, including the first.
Since the first pointer held the absolute address of the first
RAM table, this results in a list of displacements from the first
RAM table to each of the other tables. These seven two-byte
displacements are then written from the temporary area to the
file via 103. These are the first fourteen bytes of the SAVE file.
(See Figure 10-1.)
The first RAM table is the 256-byte buffer, which will not be
SAVEd. This is why the seven two-byte fields at the beginning
of the SAVEd file hold values exactly 256 more than the true
82
Chapter Ten
displacement of the tables they point to. (The LOAD procedure
will resolve the 256-byte discrepancy.)
The next operation is to write the three needed RAM
tables. The total length of these tables is determined from the
value in the seventh entry in the displacement list, minus 256.
To write the three entries, we point to the start of the Variable
Name Table and call 104, with the length of the three tables.
This saves the second part of the file format.
The file is then closed and XSAVE returns to Execution
Control.
XLOAD ($BAFB)
The LOAD statement is implemented at the XLOAD label
located at $BAFB.
XLOAD first opens the specified load file for input by
calling ELADVC. BASIC reads the first fourteen bytes from the
file into a temporary area starting at $500. These fourteen bytes
are the seven RAM table displacements created by SAVE.
The first two bytes will always be zero, according to the
SAVE file format. (See Figure 10-1.) BASIC tests these two
bytes for zero values. If these bytes are not zero, BASIC
assumes the file is not a valid SAVE file and exits via the
ERRNSF, which generates error code 21 (Load File Error).
If this is a valid SAVE file, the value in the pointer at $80
(Low Memory Address) is added to each of the seven displace-
ments in the temporary area. These values will be the memory
addresses of the three RAM tables, if and when they are read
into memory.
The seventh pointer in the temporary area contains the
address where the end of the Statement Table will be. If this
address exceeds the current system high memory value, the
routine exits via ERRPTL, which generates error code 19 (Load
Program Too Big).
If the program will fit, the seven addresses are moved from
the temporary area to the RAM table pointers at $80. The
second part of the file is then loaded into the area now pointed
to by the Variable Name Table pointer $82. The file is closed,
CLR is executed, and a test for RUN is made.
If RUN called XLOAD, then a value of $FF was pushed
onto the CPU stack. If RUN did not call XLOAD, then $00 was
pushed onto the CPU stack. If RUN was the caller, then an RTS
is done.
83
Chapter Ten
If XLOAD was entered as a result of a LOAD or CLOAD
statement, then XLOAD exits directly to the Program Editor,
not to Execution Control.
CSAVE and CLOAD
The CSAVE and CLOAD statements are special forms of SAVE
and LOAD. These two statements assume that the
SAVE/LOAD device is the cassette device.
CSAVE is not quite the same as SAVE "C:". Using SAVE
with the "C:" device name will cause the program to be saved
using long cassette inter-record gaps. This is a time waster, and
CSAVE uses short inter-record gaps.
CSAVE starts at XCSAVE ($BBAC). CLOAD starts at
XCLOAD($BBA4).
84
Chapter Eleven
The LIST and ENTER
Statements
LIST can be used to store a program on an external device and
ENTER can retrieve it. The difference between LOAD-SAVE
and LIST-ENTER is that LOAD-SAVE deals with the tokenized
program, while LIST-ENTER deals with the program in its
source (ATASCII) form.
The ENTER Statement
BASIC is in ENTER mode whenever a program is not
RUNning. By default the Program Editor looks for lines to be
ENTERed from the keyboard, but the editor handles all
ENTERed lines alike, whether they come from the keyboard or
not.
The Enter Device
To accomplish transparency of all input data (not just ENTERed
lines), BASIC maintains an enter device indicator, ENTDTD
($B4). When a BASIC routine (for example, the INPUT
simulation routine) needs data, an I/O operation is done to the
IOCB specified in ENTDTD. When the value in ENTDTD is
zero, indicating IOCB 0, input will come from the keyboard.
When data is to come from some other device, ENTDTD
contains a number indicating the corresponding IOCB. During
coldstart initialization, the enter device is set to IOCB 0. It is
also reset to at various other times.
XENTER ($BACB)
The XENTER routine is called by Execution Control to simulate
the ENTER statement. XENTER opens IOCB 7 for input using
the specified < filespec > , stores a 7 in the enter device
ENTDTD, and then jumps to the start of the editor.
Entering from a Device
When the Program Editor asks GLGO, the get line routine
($BA92), for the next line, GLGO tells CIO to get a line from the
85
Chapter Eleven
device specified in ENTDTD — in this case, from IOCB 7. The
editor continues to process lines from IOCB 7 until an end-of-
file error occurs. The IOTEST routine detects the EOF
condition, sees that we are using IOCB 7 for ENTER, closes
device 7, and jumps to SNX2 to reset the enter device
(ENTDTD) to and print the READY message before restarting
at the beginning of the editor.
The LIST Statement
The routine which simulates the LIST statement, XLIST, is
actually another example of a language translator, complete
with symbols and symbol-combining rules. XLIST translates
the tokens generated by Atari BASIC back into the semi-
English BASIC statements in ATASCII. This translation is a
much simpler task than the one done by the pre-compiler,
since XLIST can assume that the statement to be translated is
syntactically correct. All that is required is to translate the
tokens and insert blanks in the appropriate places.
The List Device
BASIC maintains a list device indicator, LISTDTD ($B5),
similar to the enter device indicator discussed earlier.
When a BASIC routine wants to output some data (an error
message, for example), the I/O operation is done to the device
(IOCB) specified in LISTDTD.
During coldstart initialization and at various other times,
LISTDTD is set to zero, representing IOCB 0, the editor, which
will place the output on the screen. Routines such as XPRINT
or XLIST can change the LIST device to indicate some other
IOCB. Thus the majority of the BASIC routines need not be
concerned about the output's destination.
Remember that IOCB is always open to the editor, which
gets input from the keyboard and outputs to the screen. IOCB 6
is the S: device, the direct access to graphics screen, which is
used in GRAPHICS statements. Atari BASIC uses IOCB 7 for
I/O commands that allow different devices, like SAVE, LOAD,
ENTER, and LIST.
XLIST ($B483)
The XLIST routine considers the output's destination in its
initialization process and then forgets about it. It looks at the
first expression in the tokenized line. If it is the < filespec >
86
Chapter Eleven
string, XLIST calls a routine to open the specified device using
IOCB 7 and to store a 7 in LISTDTD. All of XLIST's other
processing is exactly the same, regardless of the LISTed data's
final destination.
XLIST marks its place in the Statement Table by calling a
subroutine of XGOSUB to put a GOSUB type entry on the
Runtime Stack. Then XLIST steps through the Statement Table
in the same way that Execution Control does, using Execution
Control's line parameters and subroutines. When XLIST is
finished, Execution Control takes the entry off the Runtime
Stack and continues.
The XLIST routine, assuming it is to LIST all program
statements, sets default starting and ending line numbers of
(in TSLNUM) and $7FFF (in LELNUM).
XLIST then determines whether line numbers were
specified in the tokenized line that contained the LIST
statement. XLIST compares the current index into the line
(STINDEX) to the displacement to the next statement
(NXTSTD). If STINDEX is not pointing to the next statement,
at least one line number is specified. In this case, XLIST calls a
subroutine of Execute Expression to evaluate the line number
and convert it to a positive integer, which XLIST stores in
TSLNUM as the starting line number.
If a second line number is specified, XLIST calls Execute
Expression again and stores the value in LELNUM as the final
line to LIST. If there is no second line number, then XLIST
makes the ending line number equal to the starting line
number, and only one line will be LISTed. If no line numbers
were present, then TSLNUM and LELNUM still contain their
default values, and all the program lines will be LISTed.
XLIST gets the first line to be LISTed by calling the
Execution Control subroutine GETSTMT to initialize the line
parameters to correspond to the line number in TSLNUM. If
we are not at the end of the Statement Table, and if the current
line's number is less than or equal to the final line number to be
LISTed, XLIST calls a subroutine :LLINE to list the line.
After LISTing the line, XLIST calls Execution Control's
subroutines to point to the next line. LISTing continues in this
manner until the end of the Statement Table is reached or until
the final line specified has been printed.
When XLIST is finished, it exits via XRTN at $B719, which
makes the LIST statement the current statement again and then
returns to Execution Control.
87
Chapter Eleven
LIST Subroutines
:LLINE ($B55C)
The :LLINE routine LISTs the current line (the line whose
address is in STMCUR).
:LLINE gets the line number from the beginning of the
tokenized line. The floating point package is called to convert
the integer to floating point and then to printable ATASCII. The
result is stored in the buffer indicated by INBUFF. :LLINE calls
a subroutine to print the line number and then a blank.
For every statement in the line, :LLINE sets STINDEX to
point to the statement name token and calls the :LSTMT
routine ($B590) to LIST the statement. When all statements
have been LISTed, :LLINE returns to its caller, XLIST.
:LSTMT($B590)
The :LSTMT routine LISTs the statement which starts at the
current displacement (in STINDEX) into the current line. This
routine does the actual language translation from tokens to
BASIC statements.
:LSTMT uses two subroutines, :LGCT and :LGNT, to get
the current and next token, respectively. If the end of the
statement has been reached, these routines both pull the return
address of their caller off the 6502 CPU stack and return to
:LSTMT's caller, :LLINE. Otherwise, they return the requested
token from the tokenized statement line.
The first token in a statement is the statement name token.
:LSTMT calls a routine which prints the corresponding
statement name by calling :LSCAN to find the entry and
:LPRTOKENtoprintit.
In the discussion of the Program Editor we saw that an
erroneous statement was given a statement name of ERROR
and saved in the Statement Table. If the current statement is
this ERROR statement or is REM or DATA, :LSTMT picks up
each remaining character in the statement and calls PRCHAR
($BA9F) to print the character.
Each type of token is handled differently. :LSTMT
determines the type (variable, numeric constant, string
constant, or operator) and goes to the proper code to translate
it.
Variable Token. A variable token has a value greater than or
equal to $80. When :LSTMT encounters a variable token, it
88
Chapter Eleven
turns off the most significant bit to get an index into the
Variable Name Table. :LSTMT asks the :LSCAN routine to get
the address of this entry. :LSTMT then calls :LPRTOKEN
($B535) to print the variable name. If the last character of the
name is (, the next token is an array left parenthesis operator,
and :LSTMT skips it.
Numeric Constant Token. A numeric constant is indicated by
a token of $0E. The next six bytes are a floating point number.
:LSTMT moves the numeric constant from the tokenized line to
FRO ($D4) and asks the floating point package to convert it to
ATASCII. The result is in a buffer pointed to by INBUFF.
:LSTMT moves the address of the ATASCII number to
SRC ADR and tells :LPRTOKEN to print it.
String Constant Token. A string constant is indicated by a
token of $0F. The next byte is the length of the string followed
by the actual string data. Since the double quotes are not stored
with a string constant, :LSTMT calls PRCHAR ($BA9F) to print
the leading double quote. The string length tells :LSTMT how
many following characters to print without translation.
:LSTMT repeatedly gets a character and calls PRCHAR to print
it until the whole string constant has been processed. It then
asks PRCHAR to print the ending double quote.
Operator Token. An operator token is any token greater than
or equal to $10 and less than $80. By subtracting $10 from the
token value, :LSTMT creates an index into the Operator Name
Table. :LSTMT calls :LSCAN to find the address of this entry. If
the operator is a function (token value greater than or equal to
$3D), :LPROTOKEN is called to print it. If this operator is not a
function but its name is alphabetic (such as AND), the name is
printed with a preceding and following blank. Otherwise,
:LPRTOKEN is called to print just the operator name.
:LSCAN ($B50C)
This routine scans a table until it finds the translation of a token
into an ATASCII name. A token's value is based on its table
entry number; therefore, the entry number can be derived by
modifying the token. For example, a variable token is created
by machine-language ORing the table entry number of the
variable name with $80. The entry number can be produced by
ANDing out the high-order bit of the token. It is this entry
number, stored in SCANT, that the :LSCAN routine uses.
89
Chapter Eleven
The tables scanned by :LSCAN have a definite structure.
Each entry consists of a fixed length portion followed by a
variable length ATASCII portion. The last character in the
ATASCII portion has the high-order bit on. Using these facts,
:LSCAN finds the entry corresponding to the entry number in
SCANT and puts the address of the ATASCII portion in
SCRADR.
:LPRTOKEN ($B535)
This routine's task is to print the string of ATASCII characters
whose address is in SCRADR. :LPRTOKEN makes sure the
most significant bit is off (except for a carriage return) and
prints the characters one at a time until it has printed the last
character in the string (the one with its most significant bit on).
90
Chapter Twelve
Atari Hardware
Control Statements
The Atari Hardware Control Statements allow easy access to
some of the computer's graphics and audio capabilities. The
statements in this group are COLOR, GRAPHICS, PLOT,
POSITION, DRAWTO, SETCOLOR, LOCATE, and SOUND.
XGR ($BA50)
The GRAPHICS statement determines the current graphics
mode. The XGR simulation routine executes the GRAPHICS
statement. The XGR routine first closes IOCB 6. It then calls an
Execute Expression subroutine to evaluate the graphics mode
value and convert it to an integer.
XGR sets up to open the screen by putting the address of a
string "S:" into INBUFF. It creates an AUX1 and AUX2 byte
from the graphics mode integer. XGR calls a BASIC I/O routine
which sets up IOCB 6 and calls CIO to open the screen for the
specified graphics mode. Like all BASIC routines that do I/O,
XGR jumps to the IOTEST routine, which determines what to
do next based on the outcome of the I/O.
XCOLOR ($BA29)
The COLOR statement is simulated by the XCOLOR routine.
XCOLOR calls a subroutine of Execute Expression to evaluate
the color value and convert it to an integer. XCOLOR saves this
value (MOD 256) in BASIC memory location COLOR ($C8).
This value is later retrieved by XPLOT and XDRAWTO.
XSETCOLOR ($B9B7)
The routine that simulates the SETCOLOR statement,
XSETCOLOR, calls a subroutine of Execute Expression to
evaluate the color register specified in the tokenized line. The
Execute Expression routine produces a one-byte integer. If the
value is not less than 5 (the number of color registers),
XSETCOLOR exits via the Error Handling Routine at entry
point ERVAL. Otherwise, it calls Execute Expression to get two
more integers from the tokenized line.
91
Chapter Twelve
To calculate the color value, XSETCOLOR multiplies the
first integer (MOD 256) by 16 and adds the second (MOD 256).
Since the operating system's five color registers are in
consecutive locations starting at $2C4, XSETCOLOR uses the
register value specified as an index to the proper register
location and stores the color value there.
XPOS ($BA16)
The POSITION statement, which specifies the X and Y
coordinates of the graphics cursor, is simulated by the XPOS
routine.
XPOS uses a subroutine of Execute Expression to evaluate
the X coordinate of the graphics window cursor and convert it
to an integer value. The two-byte result is stored in the
operating system's X screen coordinate location (SCRX at $55).
This is the column number or horizontal position of the cursor.
XPOS then calls another Execute Expression subroutine to
evaluate the Y coordinate and convert it to a one-byte integer.
The result is stored in the Y screen coordinate location (SCRY at
$54). This is the row number, or vertical position.
XLOCATE ($BC95)
XLOCATE, which simulates the LOCATE statement, first calls
XPOS to set up the X and Y screen coordinates. Next it
initializes IOCB 6 and joins a subroutine of XGET to do the
actual I/O required to get the screen data into the variable
specified.
XPLOT ($BA76)
XPLOT, which simulates the PLOT statement, first calls XPOS
to set the X and Y coordinates of the graphics cursor. XPLOT
gets the value that was saved in COLOR ($C8) and joins a PUT
subroutine (PRCX at $BAA1) to do the I/O to IOCB 6 (the
screen).
XDRAWTO ($BA31)
The XDRAWTO routine draws a line from the current X,Y
screen coordinates to the X,Y coordinates specified in the
statement. The routine calls XPOS to set the new X,Y
coordinates. It places the value from BASIC'S memory location
COLOR into OS location SVCOLOR ($2FB). XDRAWTO does
some initialization of IOCB 6 specifying the draw command
($11). It then calls a BASIC I/O routine which finishes the
92
Chapter Twelve
initialization of IOCB 6 and calls CIO to draw the line. Finally,
XDRAWTO jumps to the IOTEST routine, which will
determine what to do next based on the outcome of the I/O.
XSOUND($B9DD)
The Atari computer hardware uses a set of memory locations to
control sound capabilities. The SOUND statement gives the
user access to some of these capabilities. The XSOUND
routine, which simulates the SOUND statement, places fixed
values in some of the sound locations and user specified values
in others.
The XSOUND routine uses Execute Expression to get four
integer values from the tokenized statement line. If the first
integer (voice) is greater than or equal to 4, the Error Handling
Routine is invoked at ERVAL.
The OS audio control bits are all turned off by storing a
into $D208. Any bits left on from previous serial port usage are
cleared by storing 3 in $D20F.
The Atari has four sound registers (one for each voice)
starting at $D200. The first byte of each two-byte register
determines the pitch (frequency). In the second byte, the four
most significant bits are the distortion, and the four least
significant bits are the volume.
The voice value mentioned earlier is multiplied by 2 and
used as an index into the sound registers. The second value
from the tokenized line is stored as the pitch in the first byte of
one of the registers ($D200, $D202, $D204, or $D206),
depending on the voice index. The third value from the
tokenized line is multiplied by 16 and the fourth value is added
to it to create the value to be stored as distortion/volume. The
voice, times 2, is again used as an index to store this value in
the second byte of a sound register ($D201, $D203, $D205, or
$D207). The XSOUND routine then returns to Execution
Control.
93
Chapter Thirteen
External Data
I/O Statements
The external data I/O statements allow data which is not part of
the BASIC source program to flow into and out of BASIC.
External data can come from the keyboard, a disk, or a cassette.
BASIC can also create external information by sending data to
external devices such as the screen, a printer, or a disk.
The INPUT and GET statements are the primary
statements used for obtaining information from external
devices. The PRINT and PUT statements are the primary
statements for sending data to external devices.
XIO, LPRINT, OPEN, CLOSE, NOTE, POINT and
STATUS are specialized I/O statements. LPRINT is used to
print a single line to the "P:" device. The other statements
assist in the I/O process.
XINPUT($B316)
The execution of the INPUT statement starts at XINPUT
($B316).
Getting the Input Line. The first action of XINPUT is to
read a line of data from the indicated device. A line is any
combination of up to 255 characters terminated by the EOL
character ($9B). This line will be read into the buffer located at
$580.
If the INPUT statement contained was followed by
# < expression > , the data will be read from the IOCB whose
number was specified by < expression > . If there was no
# < expression > , IOCB will be used. IOCB is the screen
editor and keyboard device (E:). If IOCB is indicated, the
prompt character (?) will be displayed before the input line
request is made; otherwise, no prompt is displayed.
Line Processing. Once the line has been read into the
buffer, processing of the data in that line starts at XINA
($B335). The input line data is processed according to the
tokens in the INPUT (or READ) statements. These tokens are
numeric or string variables separated by commas.
95
Chapter Thirteen
Processing a Numeric Variable. If the new token is a
numeric variable, the CVAFP routine is called to convert the
next characters in the input line to a floating point number. If
this conversion does not report an error, and if the next input
line character is a comma or an EOL, the floating point value is
processed.
The processing of a valid numeric input value consists of
calling RTNVAR to return the variable and its new value to the
Variable Value Table.
If there is an error, INPUT processing is aborted via the
ERRINP routine. If there is no error, but the user has hit
BREAK, the process is aborted via XSTOP. If there is no abort,
XINX ($B389) is called to continue with INPUT'S next task.
Processing a String Variable. If the next statement token is
a string variable, it is processed at XISTR ($B35E). This routine
is also used by the READ statement. If the calling statement is
INPUT, then all input line characters from the current character
up to but not including the EOL character are considered to be
part of the input string data. If the routine was called by READ,
all characters up to but not including the next comma or EOL
are considered to be part of the input string.
The process of assigning the data to the string variable is
handled by calling RISASN ($B386). If RISASN does not abort
the process because of an error like DIMENSION TOO
SMALL, XINX is called to continue with INPUT'S next task.
XINX. The XINX ($B389) routine is entered after each variable
token in an INPUT or a READ statement is processed.
If the next token in the statement is an EOL, the
INPUT/READ statement processing terminates at XIRTS
($B3A1). XIRTS restores the line buffer pointer ($80) to the
RAM table buffer. It then restores the enter device to IOCB
(in case it had been changed to some other input device).
Finally, XIRTS executes an RTS instruction.
If the next INPUT/READ statement token is a comma, more
input data is needed. If the next input line character is an EOL,
another input line is obtained. If the statement was INPUT, the
new line is obtained by entering XINO ($B326). If the statement
was READ, the new line is obtained by entering XRD3 ($B2D0).
The processing of the next INPUT/READ statement
variable token continues at XINA.
96
Chapter Thirteen
XGET ($BC7F)
The GET statement obtains one character from some specified
device and assigns that character to a scalar (non-array)
numeric variable.
The execution of GET starts at XGET ($BC7F) with a call to
GIODVC. GIODVC will set the I/O device to whatever number
is specified in the # < expression > or to IOCB zero if no
# < expression > was specified. (If the device is IOCB (E:), the
user must type RETURN to force E: to terminate the input.)
The single character is obtained by calling 103. The
character is assigned to the numeric variable by calling ISVAR1
($BD2D). ISVAR1 also terminates the GET statement
processing.
PRINT
The PRINT statement is used to transmit text data to an
external device. The arguments in the PRINT statement are a
list of numeric and/or string expressions separated by commas
or semicolons. If the argument is numeric, the floating point
value is converted to text form. If the argument is a string, the
string value is transmitted as is.
If an argument separator is a comma, the arguments are
output in tabular fashion: each new argument starts at the next
tab stop in the output line, with blanks separating the
arguments.
If the argument separator is a semicolon, the transmitted
arguments are appended to each other without separation.
The transmitted line is terminated with an EOL, unless a
semicolon or comma directly precedes the statement's EOL or
statement separator (:).
XPRINT ($B3B6). The PRINT routine begins at XPRINT
($B3B6). The tab value is maintained in the PTABW ($C9) cell.
The cell is initialized with a value of ten during BASIC'S cold
start, so that commas in the PRINT line cause each argument to
be displaced ten positions after the beginning of the last
argument. The user may POKE PTABW to set a different tab
value.
XPRINT copies PTABW to SCANT ($AF). SCANT will be
used to contain the next multiple-of-PTABW output line
displacement — the column number of the next tab stop.
COX is initialized to zero and is used to maintain the
current output column or displacement.
97
Chapter Thirteen
XPRO. XPRINT examines the next statement token at XPRO
($B3BE), classifies it, and executes the proper routine.
# Token. If the next token is #, XPRIOD ($B437) is entered.
This routine modifies the list device to the device specified in
the #< expression > . XPRO is then entered to process the next
token.
, Token. The XPTAB ($B419) routine is called to process
the , token. Its job is to tab to the next tab column.
If COX (the current column) is greater than SCANT, we
must skip to the next available tab position. This is done by
continuously adding PTABW to SCANT until COX is less than
or equal to SCANT. When COX is less than SCANT, blanks
($20) are transmitted to the output device until COX is equal to
SCANT.
The next token is then examined at XPRO.
EOL and : Tokens. The XPEOS ($B446) routine is entered
for EOL and : tokens. If the previous token was a ; or , token,
PRINT exits at XPRTN ($B458). If the previous token was not a ;
or , token, an EOL character is transmitted before exiting via
XPRTN.
; Token. No special action is taken for the ; token except to
go to XPRO to examine the next token.
Numbers and Strings. If the next token is not one of the
above tokens, Execute Expression is called to evaluate the
expression. The resultant value is popped from the argument
stack and its type is tested for a number or a string.
If the argument popped was numeric, it will be converted
to text form by calling CVFASC. The resulting text is
transmitted to the output device from the buffer pointed to by
INBUFF ($F3). XPRO is then entered to process the next token.
If the argument popped was a string, it will be transmitted
to the output device by the code starting at :XPSTR ($B3F8).
This code examines the argument parameters to determine the
current length of the string. When the string has been
transmitted, XPRO is entered to process the next token.
XLPRINT ($B464)
LPRINT, a special form of the PRINT statement, is used to print
a line to the printer device (P:).
98
Chapter Thirteen
The XLPRINT routine starts at $B464 by opening IOCB 7 for
output to the P: device. XPRINT is then called to do the
printing. When the XPRINT is done, IOCB 7 is closed via
CLSYS1 and LPRINT is terminated.
XPUT ($BC72)
The PUT statement sends a single byte from the expression in
the PUT statement to a specified external device.
Processing starts at XPUT ($BC72) with a call to GIODVC.
GIODVC sets the I/O device to the IOCB specified in
# < expression > . If a # < expression > does not exist, the
device will be set to IOCB zero (E:).
The routine then calls GETINT to execute PUT's expression
and convert the resulting value to a two-byte integer. The least
significant byte of this integer is then sent to the PUT device via
PRCX. PRCX also terminates the PUT processing.
XXIO ($BBE5)
The XIO statement, a general purpose I/O statement, is
intended to be used when no other BASIC I/O statement will
serve the requirements. The XIO parameters are an IOCB I/O
command, an IOCB specifying expression, an AUX1 value, an
AUX2 value, and finally a string expression to be used as a
filespec parameter.
XIO starts at XXIO ($BBE5) with a call to GIOCMD.
GIOCMD gets the IOCB command parameter. XIO then
continues at XOP1 in the OPEN statement code.
XOPEN ($BBEB)
The OPEN statement is used to open an external device for
input and/or output. OPEN has a # < expression > , the open
type parameter (AUX1), an AUX2 parameter, and a string
expression to be used as a filespec.
OPEN starts at XOPEN at $BBEB. It loads the open
command code into the A register and continues at XOP1.
XOP1 . XOP1 continues the OPEN and XIO statement
processing. It starts at $BBED by storing the A register into the
IOCMD cell. Next it obtains the AUX1 (open type) and AUX2
values from the statement.
The next parameter is the filespec string. In order to insure
that the filespec has a proper terminator, SETSEOL is called to
place a temporary EOL at the end of the string.
99
Chapter Thirteen
The XIO or OPEN command is then executed via a call to
IOl. When IOl returns, the temporary EOL at the end of the
string is replaced with its previous value by calling RSTSEOL.
OPEN and XIO terminate by calling IOTEST to insure that
the command was executed without error.
XCLOSE($BC1B)
The CLOSE statement, which closes the specified device, starts
at XCLOSE ($BC1B). It loads the IOCB close command code
into the A register and continues at GDVCIO.
GDVCIO. GDVCIO ($BC1D) is used for general purpose
device I/O. It stores the A register into the IOCMD cell, calls
GIODVC to get the device from # < expression > , then calls 107
to execute the I/O. When 107 returns, IOTEST is called to test
the results of the I/O and terminate the routine.
XSTATUS ($BC28)
The STATUS statement executes the IOCB status command.
Processing starts at XSTATUS ($BC28) by calling GIODVC to
get the device number from #< expression > . It then calls 108
with the status command in the A register. When 108 returns,
the status returned in the IOCB status cell is assigned to the
variable specified in the STATUS statement by calling ISVAR1.
ISVAR1 also terminates the STATUS statement processing.
XNOTE ($BC36)
The NOTE statement is used specifically for disk random
access. NOTE executes the Disk Device Dependent Note
Command, $26, which returns two values representing the
current position within the file for which the IOCB is open.
NOTE begins at XNOTE at $BC36. The code loads the
command value, $26, into the A register and calls GDVCIO to
do the I/O operation. When GDVCIO returns, the values are
moved from AUX3 and AUX4 to the first variable in the NOTE
statement. The next variable is assigned the value from AUX5.
XPOINT($BC4D)
The POINT statement is used to position a disk file to a
previously NOTEd location. Processing starts at XPOINT
($BC4D). This routine converts the first POINT parameter to an
integer and stores the value in AUX3 and AUX4. The second
parameter is then converted to an integer and its value stored
100
Chapter Thirteen
in AUX5. The POINT command, $25, is executed by calling
GDIOl, which is part of GDVCIO.
Miscellaneous I/O Subroutines
IOTEST. IOTEST ($BCB3) is a general purpose routine that
examines the results of an I/O operation. If the I/O processing
has returned an error, IOTEST processes that error.
IOTEST starts by calling LDlOSTA to get the status byte
from the IOCB that performed the last I/O operation. If the byte
value is positive (less than 128), IOTEST returns to the caller.
If the status byte is negative, the I/O operation was
abnormal and processing continues at SICKIO.
If the I/O aborted due to a BREAK key depression, BRKBYT
($11) is set to zero to indicate BREAK. If a LOAD was in
progress when BREAK was hit, exit is via COLDSTART;
otherwise IOTEST returns to its caller.
If the error was not from IOCB 7 (the device BASIC uses),
the error status value is stored in ERRNUM and ERROR is
called to print the error message and abort program execution.
If the error was from IOCB 7, then IOCB 7 is closed and
ERROR is called with the error status value in ERRNUM —
unless ENTER was being executed, and the error was an end-
of-file error. In this case, IOCB 7 is closed, the enter device is
reset to IOCB 0, and SNX2 is called to return control to the
Program Editor.
I/O Call Routine. All I/O is initiated from the routine starting
at IOl ($BD0A). This routine has eight entry points, IOl
through 108, each of which stores predetermined values in an
IOCB. All IOn entry points assume that the X register contains
the IOCB value, times 16.
101 sets the buffer length to 255.
102 sets the buffer length to zero.
103 sets the buffer length to the value in the Y register plus
a most-significant length byte of zero.
104 sets the buffer length from the values in the Y, A
register pair, with the A register being the most-significant
value.
105 sets the buffer address from the value in the INBUFF
cell($F3).
106 sets the buffer address from the Y, A register pair. The
A register contains the most significant byte.
101
Chapter Thirteen
107 sets the I/O command value from the value in the
IOCMD cell.
108 sets the I/O command from the value in the A register.
All of this is followed by a call to the operating system CIO
entry point. This call executes the I/O. When CIO returns, the
general I/O routine returns to its caller.
102
Chapter Fourteen
Internal I/O
Statements
The READ, DATA, and RESTORE statements work together to
allow the BASIC user to pass predetermined information to his
or her program. This is, in a sense, internal I/O.
XDATA ($A9E7)
The information to be passed to the BASIC program is stored in
one or more DATA statements. A DATA statement can occur
any place in the program, but execution of a DATA statement
has no effect.
When Execution Control encounters a DATA statement, it
expects to process this statement just like any other. Therefore
an XDATA routine is called, but XDATA simply returns to
Execution Control.
XREAD ($B283)
The XREAD routine must search the Statement Table to find
DATA. It uses Execution Control's subroutines and line
parameters to do this. When XREAD is done, it must restore
the line parameters to point to the READ statement. In order to
mark its place in the Statement Table, XREAD calls a
subroutine of XGOSUB to put a GOSUB-type entry on the
Runtime Stack.
The BASIC program may need to READ some DATA, do
some other processing, and then READ more DATA.
Therefore, XREAD needs to keep track of just where it is in
which DATA statement. There are two parameters that provide
for this. DATALN ($B7) contains the line number at which to
start the search for the next DATA statement. DATAD ($B6)
contains the displacement of the next DATA element in the
DATALN line. Both values are set to zero as part of RUN and
CLR statement processing.
XREAD calls Execution Control's subroutine GETSTMT to
get the line whose number is stored in DATALN. If this is the
first READ in the program and a RESTORE has not set a
103
Chapter Fourteen
different line number, DATALN contains zero, and GETSTMT
will gel the first line in the program. On subsequent READs,
GETSTM7' gets the last DATA statement that was processed by
the previous READ.
After getting its first line, XREAD calls the XRTN routine to
restore Execution Control's line parameters.
The current line number is stored in DATALN. XREAD
steps through the line, statement by statement, looking for a
DATA statement. If the line contains no DATA statement, then
subsequent lines and statements are examined until a DATA
statement is found.
When a DATA statement has been found, XREAD inspects
the elements of the DATA statement until it finds the element
whose displacement is in DATAD.
If no DATA is found, XREAD exits via the ERROOD entry
point in the Error Handling Routine. Otherwise, a flag is set to
indicate that a READ is being done, and XREAD joins XINPUT
at :XINA. XINPUT handles the assignment of the DATA values
to the variables. (See Chapter 13.)
XREST ($B26B)
The RESTORE statement allows the BASIC user to re-READ a
DATA statement or change the order in which the DATA
statements are processed. The XREST routine simulates
RESTORE.
XREST sets DATALN to the line number given, or to zero if
no line number is specified. It sets DATAD to zero, so that the
next READ after a RESTORE will start at the first element in the
DATA line specified in DATALN.
104
Chapter Fifteen
Miscellaneous
Statements
XDEG ($B261) and XRAD ($B266)
The transcendental functions such as SIN or COS will work
with either degrees or radians, depending on the setting of
RADFLG ($FB). The DEG and RAD statements cause RADFLG
to be set. These statements are simulated by the XDEG and
XRAD routines, respectively.
The XDEG routine stores a six in RADFLG. XRAD sets it to
zero. These particular values were chosen because they aid the
transcendental functions in their calculations.
RADFLG is set to zero during BASIC'S initialization
process and also during simulation of the RUN statement.
XPOKE ($B24C)
The POKE statement is simulated by the XPOKE routine.
XPOKE calls a subroutine of Execute Expression to get the
address and data integers from the tokenized line. XPOKE then
stores the data at the specified address.
XBYE ($A9E8)
The XBYE routine simulates the BYE statement. XBYE closes all
IOCBs (devices and files) and then jumps to location $E471 in
the Operating System. This ends BASIC and causes the memo
pad to be displayed.
XDOS ($A9EE)
The DOS statement is simulated by the XDOS routine. The
XDOS routine closes all IOCBs and jumps to whatever address
is stored in location $0A. This will be the address of DOS if
DOS has been loaded. If DOS has not been loaded, $0A will
point to the memo pad.
XLET ($AAEO)
The LET and implied LET statements assign values to
variables. They both invoke the XLET routine, which consists
of the Execute Expression routines. (See Chapter 7.)
105
Chapter Fifteen
XREM ($A9E7)
The REM statement is for documentation purposes only and
has no effect on the running program. The routine which
simulates REM, XREM, simply executes an RTS instruction to
return to Execution Control.
XERR($B91E)
When a line containing a syntax error is entered, it is given a
special statement name token to indicate the error. The entire
line is flagged as erroneous no matter how many previously
good statements are in the line. The line is then stored in the
Statement Table.
The error statement is processed just like any other.
Execution Control calls a routine, XERR, which is one of the
entry points to the Error Handling Routine. It causes error 17
(EXECUTION OF GARBAGE).
XDIM($B1D9)
The DIMension statement, simulated by the XDIM routine,
reserves space in the String/ Array Table for the DIMensioned
variable .
The XDIM routine calls Execute Expression to get the
variable to be DIMensioned from the Variable Value Table. The
variable entry is put into a work area. In the process, Execute
Expression gets the first and second DIMension values and sets
a default of zero if only one value is specified.
XDIM checks to see if the variable has already been
DIMensioned. If the variable was already DIMensioned, XDIM
exits via the ERRDIM entry point in the Error Handling
Routine. If not, a bit is set in the variable type byte in the work
area entry to mark this variable as DIMensioned.
Next, XDIM calculates the amount of space required. This
calculation is handled differently for strings and arrays.
DIMensioning an Array. XDIM first increments both
dimension values by one and then multiplies them together to
get the number of elements in the array. XDIM multiplies the
result by 6 (the length of a floating point number) to get the
number of bytes required. EXPAND is called to expand the
String/ Array Table by that amount.
XDIM must finish building the variable entry in the work
area. It stores the first and second dimension values in the
entry. It also stores the array's displacement into the
106
Chapter Fifteen
String/ Array Table. It then calls an Execute Expression
subroutine to return the variable to the Variable Value Table.
(See Chapter 3.)
DIMensioning a String. Reserving space for a string in the
String/Array Table is much simpler. XDIM merely calls the
EXPAND routine to expand by the user-specified size.
XDIM must also build the Variable Value Table entry in the
work area. It sets the current length to and the maximum
length to the DIMensioned value. The displacement of the
string into the String/ Array Table is also stored in the variable.
XDIM then calls a subroutine of Execute Expression to return
the variable entry to the Variable Value Table. (See Chapter 3.)
107
Chapter Sixteen
Initialization
When the Atari computer is powered up with the BASIC
cartridge in place, the operating system does some processing
and then jumps to a BASIC routine. Between the time that
BASIC first gets control and the time it prints the READY
message, initialization takes place. This initialization is called a
cold start. No data or tables are preserved during a cold start.
Initialization is repeated if things go terribly awry. For
example, if there is an I/O error while executing a LOAD
statement, BASIC is totally confused. It gives up and begins all
over again with the COLDSTART routine.
Sometimes a less drastic partial initialization is necessary.
This process is handled by the WARMSTART routine, in which
some tables are preserved.
Entering the NEW statement, simulated by the XNEW
routine, has almost the same effect as a cold start.
COLDSTART ($A000)
Two flags, LOADFLG and WARMFLG, are used to determine
if a cold or warm start is required.
The load flag, LOADFLG ($CA), is zero except during the
execution of a LOAD statement. The XLOAD routine sets the
flag to non-zero when it starts processing and resets it to zero
when it finishes. If an I/O error occurs during that interval,
IOTEST notes that LOADFLG is non-zero and jumps to
COLDSTART.
The warm-start flag, WARMFLG ($08), is never set by
BASIC. It is set by some other routine, such as the operating
system or DOS. If WARMFLG is zero, a cold start is done. If it
is non-zero, a warm start is done. During its power-up
processing, before BASIC is given control, OS sets WARMFLG
to zero to request a cold start. During System Reset processing,
OS sets the flag to non-zero, indicating a warm start is desired.
If DOS has loaded any data into BASIC'S program area
during its processing, it will request a cold start.
The COLDSTART routine checks both WARMFLG and
LOADFLG to determine whether to do a cold or warm start. If
a cold start is required, COLDSTART initializes the 6502 CPU
109
Chapter Sixteen
stack and clears the decimal flag. The rest of its processing is
exactly the same as if the NEW statement had been entered.
XNEW($A00C)
The NEW statement is simulated by the XNEW routine. XNEW
resets the load flag, LOADFLG, to zero. It initializes the zero-
page pointers to BASIC'S RAM tables. It reserves 256 bytes at
the low memory address for the multipurpose buffer and
stores its address in the zero-page pointer located at $80.
Since none of the RAM tables are to retain any data, their zero-
page pointers ($82 through $90) are all set to low memory plus
256.
The Variable Name Table is expanded by one byte, which is
set to zero. This creates a dummy end-of-table entry.
The Statement Table is expanded by three bytes. The line
number of the direct statement ($8000) is stored there along
with the length (three). This marks the end of the Statement
Table.
A default tab value of 10 is set for the PRINT statement.
WARMSTART ($A04D)
A warm start is the least drastic of the three types of
initialization. Everything the WARMSTART routine does is also
done by COLDSTART and XNEW.
The stop line number (STOPLN), the error number
(ERRNUM), and the DATA parameters (DATALN and DATAD)
are all set to zero. The RADFLG flag is set to zero, indicating
that transcendental functions are working in radians. The
break byte (BRKBYT) is set off and $FF is stored in TRAPLN to
indicate that errors are not being trapped.
All IOCBs (devices and files) are closed.
The enter and list devices (ENTDTD and LISTDTD) are set
to zero to indicate the keyboard and the screen, respectively.
Finally, the READY message is printed and control passes
to the Program Editor.
110
Part Two
Accessing
Atari BASIC
-J
Introduction to
Part Two
Congratulations! If you have read all of Part 1, you are through
the hard stuff. In Part 2, we hope to teach you how to use at
least some of the abundance of information presented in the
Source Listing and in Part 1. In particular, we will show you
how to examine the various RAM and ROM tables used by
BASIC.
The examples and suggestions will be written in Atari
BASIC. But those of you who are true-blue assembly language
fanatics should have little trouble translating the concepts to
machine code, especially with the source listing to guide you.
Would that we could present an example program or
concept for each possible aspect of the BASIC interpreter, but
space does not allow it — nor would it be appropriate. For
example, although we will present here a program to list all
keywords and token values used by BASIC, we will not explore
the results (usually disastrous) of changing token values within
a BASIC program.
Part 2 begins with a pair of introductory chapters. If you are
experienced at hexadecimal-to-decimal conversions and with
the concepts of word and byte PEEKs and POKEs, you may
wish to skip directly to Chapter 3.
113
Chapter One
Hexadecimal
Numbers
The word hexadecimal means, literally, "of six and ten." It
implies, however, a number notation which uses 16 as its base
instead of 10. Hexadecimal notation is used as a sort of
shorthand for the eight-digit binary numbers that the 6502
understands. If Atari BASIC understood hexadecimal numbers
and we all had eight fingers on each hand, there would be no
need for this chapter. Instead, to use this book you have to
make many conversions back and forth between hexadecimal
("hex") and decimal notation. Many BASIC users have never
had to learn that process.
Virtually all the references to addresses and other values in
this book are given in hexadecimal notation (or simply "hex"
to us insiders). For example, we learn that the Atari BASIC
ROM cartridge has $A000 for its lowest address and that
location $80 contains a pointer to BASIC'S current LOMEM.
But what does all that mean?
First of all, if you are not familiar with 6502 assembly
language, let me point out that there is a convention that a
number preceded by a dollar sign ($80) is a hexadecimal
number, even if it contains only decimal digits. Also, notice
that in the Source Listing all numbers in the first three columns
are hexadecimal, even though the dollar sign is not present. (To
the right of those columns, though, only those numbers
preceded by a dollar sign are in hex.)
Now, suppose I wanted to look at the contents of location
$A4AF (SNTAB in the listing). Realistically, the only way to
look at a memory location from BASIC is via the PEEK function
(and see the next chapter if you are not sure how to use PEEK
in this situation). But BASIC'S language syntax requires a
decimal number with PEEK — for instance, PEEK (15).
Obviously, we need some way to convert from hexadecimal
to decimal. Aside from going out and buying one of the
calculators made just for this purpose, the best way is probably
to let your computer help you. And the computer can help you
115
Chapter One
even if you only understand BASIC. As an example, here's a
BASIC program that will convert hex to decimal notation:
10 DIM HEX$(23) ,NUM$(4)
20 HEX$="@ABCDEFGHI#######JKLMNO"
30 CVHEX=9000
100 PRINT : PRINT "GIVE ME A HEX NUMBER
110 INPUT NUM$
120 GOSUB CVHEX
130 PRINT "HEX ";NUM$;" = DECIMAL " ; NUM
140 GOTO 100
9000 REM THE CONVERT HEX TO DECIMAL ROUTINE
9010 NUM=0
9020 FOR 1=1 TO LEN(NUM$)
9030 NUM=NUM*16+ASC(HEX$(ASC(NUM$(I) )-47) )-64
9040 NEXT I : RETURN
Now, while this program might be handy for a few
purposes, it would be much neater if we could simply use its
capabilities anytime we wanted to examine or change a location
(or its contents) referred to by a hex address or data. And so
shall it be used.
If we remove lines 100 through 140, inclusive, then any
BASIC program which incorporates the rest of the program
may change a hex number into decimal by simply
1 . placing the ATASCII form of the hex number in the
variable NUM$,
2. calling the convert routine at line 9000 (via GOSUB
CVHEX), and
3. using the result, which is returned in the variable NUM.
In the next chapter, we will immediately begin to make use
of this routine. If you are not used to hex notation, you might
do well to type in and play with this program before
proceeding.
Finally, before we leave this subject, let's examine a routine
which will allow us to go the other way — that is, convert
decimal to hex:
40 DIM DEC$(16) :DEC$="0123456789ABCDEF"
50 CVDEC=9100
100 PRINT : PRINT "GIVE ME A DECIMAL NUMBER
116
Chapter One
110 INPUT DEC:NUM=DEC
120 GOSUB CVDEC:REM ' NUM ' is destroyed by this
130 PRINT DEC;" Decimal = ";NUM$;" Hex"
140 GOTO 100
9100 REM CONVERT DECIMAL TO HEX ROUTINE
9110 DIV=4096
9120 FOR 1=1 TO 4
9130 N=INT(NUM/DIV) :NUM$(I, I)=DEC$ (N+l )
9140 NUM=NUM-DIV*N:DIV=DIV/16
9150 NEXT I
9160 RETURN
These lines are meant to be added to the previous program,
though they can be used alone if you simply add this line:
10 DIMNUM$(4)
We will use portions of these programs in later chapters,
but we may compress some of the code into fewer lines simply
to save wear and tear on our fingers. If you study these
routines, you'll recognize them in their transformed versions.
117
Chapter Two
PEEKing and
POKEing
In contrast to languages which include direct machine
addressing capability, like "C" and Forth, and in contrast to
"school" languages like Pascal and Fortran, which specifically
prevent such addressing, BASIC provides a sort of halfway
measure in machine accessibility.
POKE is a BASIC statement. Its syntax is
POKE < address > , < data > . Naturally, both < address > and
< data > may be constants, variables, or even full-blown
expressions:
POKE 82,0: REM change left screen margin to zero
produces the same result as
LEFTMARGIN = 82:POKE LEFTMARGIN,0
PEEK, on the other hand, is a BASIC function. It cannot
stand alone as a statement. To use PEEK, we either PRINT the
value (contents) of a PEEKed location, assign a PEEKed value
to a variable, or test the value for some condition:
POKE 82, PEEK(82) + 1 : REM move the left margin in a
space
PRINT PEEK(106) : REM where is the top of system
memory?
IF PEEK(195) = 136 THEN PRINT "End of File"
In the first example, the number POKEd into 82 will be
whatever number was stored before, plus 1. As explained in
Part 1, the PEEK function is executed before the POKE.
An aside: Just where did I get those addresses I used in the
PEEKs and POKEs? One way to find them is to peruse the
listings of Atari's operating system, available in Atari's
technical manuals set, and the listing of BASIC in this book.
Another way would be to use a book (like COMPUTE! Books'
Mapping the Atari) or a reference card designed specifically to
tell you about such addresses.
And one more thing to consider before moving on. If we
counted all of the bit patterns possible in a single 8-bit byte (like
119
Chapter Two
01010101, 11110000, and 00000001, where each 1 or represents
a single on or off bit), we would discover that there are 256
unique combinations, ranging in value from to 255. Since
each memory location can hold only one byte, it is not
surprising to learn that the PEEK function will always return a
number from to 255 ($00 to $FF). Similarly, BASIC will only
POKE a data value that is an integer from to 255. In fact,
BASIC will convert any data to be POKEd to an integer
number, rounding off any fractional parts.
So far so good. But suppose we want to examine a location
which is actually a two-byte word, such as the line number
where the last TRAPped error occurred, stored starting at
location $BA hex or 186 decimal. PEEK only lets us look at one
byte at a time. How do we look at two bytes? Simple: one byte
at a time.
In most cases, words in a 6502-based machine are stored in
memory with the least significant byte stored first. This means
that the second byte of each word is a count of the number of
256 's there are in its value, and the first byte is the leftovers.
(Or we can more properly say that the first byte contains "the
word's value modulo 256.") Confused? Let's try restating that.
In decimal arithmetic, we can count from to 9 in a single
digit. To go beyond 9, we have a convention that says the digit
second from the right represents the number of 10's in the
number, and so on.
If we consider bytes to be a computer's digits, which in
many ways they are, and if we remember that each byte may
represent any number from to 255 (or $00 to $FF), then it is
logical to say that the next byte is a count of the number of 256's
in the number. The only thing illogical is that the higher byte
comes after the lower byte (like reading 37 as "7 tens and 3
ones" instead of what we are used to).
Some examples might help:
a 6502 word
as written
think of
decima
in memory
in assembler
it as
value
0100
$0001
0*256 +1
1
00 01
$0100
1*256 +0
256
02 04
$0402
4*256 +2
1026
FFFF
$FFFF
255*256 +255
65535
So let's examine that error line location:
PRINT PEEK(186) + 256 * PEEK(187)
120
Chapter Two
Do you see it? Since the second byte is a count of the number of
256's in the value, we must multiply it by 256 to calculate its
true value.
Now, in the case of line numbers, it is well and good that
we print out a decimal value, since that is how we are used to
thinking of them. But suppose you wished to print out some of
BASIC'S tables? You might very well wish to see the hex
representations. The program presented here allows you to
specify a hex address. It then presents you with the contents of
the byte and the word found at that address, in both decimal
and hex form.
10 DIM HEX$(23) ,NUM$(4)
20 HEX$="@ABCDEFGHI ####### JKLMNO"
30 CVHEX=9000
40 DIM DEC$(16) :DEC$="0123456789ABCDEF"
50 CVDEC=9100
100 PRINT : PRINT "WHAT ADDRESS TO VIEW ";
110 INPUT NUM$: PRINT
120 PRINT "Address ";NUM$;" contains:"
130 GOSUB CVHEX : ADDR=NUM
140 NUM=PEEK(ADDR) : GOSUB CVDEC
150 PRINT , "byte " ; PEEK( ADDR) ; " - $";NUM$(3)
160 WORD=PEEK(ADDR)+256*PEEK(ADDR+l )
170 NUM=WORD: GOSUB CVDEC
180 PRINT , "word ";WORD;" = $";NUM$
190 GOTO 100
9000 REM THE CONVERT HEX TO DECIMAL ROUTINE
9010 NUM=0
9020 FOR 1=1 TO LEN(NUM$)
9030 NUM=NUM*16+ASC(HEX$(ASC(NUM$(I) )-47) )-64
9040 NEXT I: RETURN
9100 REM CONVERT DECIMAL TO HEX ROUTINE
9110 DIV=4096
9120 FOR 1=1 TO 4
9130 N=INT(NUM/DIV) :NUM$(I, l)=DEC$(N+l )
9140 NUM=NUM-DIV*N:DIV=DIV/16
9150 NEXT I
9160 RETURN
You may have noticed that lines 10 through 50 and lines
9000 to the end are the same as those used in the example
121
Chapter Two
programs in the last chapter. And did you see line 160, where
we obtained the word value by multiplying by 256?
As the last point of this chapter, we need to discuss how to
change a word value. Obviously, in Atari BASIC we can't POKE
both bytes of a word at once any more than we could retrieve
both bytes at once (although BASIC A+ can, by using the
DPOKE statement and DPEEK function). So we must invent a
mechanism to do a double POKE.
Given that the variable ADDR contains the address at
which we wish to POKE a word, and given that the variable
WORD contains the value (in decimal) of the desired word, the
following code fragment will perform the double POKE:
POKE ADDR + l,INT(WORD/256)
POKE ADDR, WORD-256*PEEK( ADDR + 1)
This is kind of sneaky code, but calculating the most
significant byte and POKEing the value in byte location
ADDR + 1 first allows us to also use it as a kind of temporary
variable in calculating the least significant byte. By PEEKing the
location that already holds the high-order byte, we can subtract
it from the original value. The remainder is WORD modulo 256
— the low-order byte.
And that's about it. Hopefully, if you were not familiar
with PEEK and POKE before, you now at least will not
approach their use with too much caution. Generally, PEEKs
will never harm either your running program or the machine,
but don't be surprised if a stray POKE or two sends your
computer off into never-never land. After all, you may have
just told BASIC to start putting your program into ROM, or
worse.
On the other hand, if you have removed your diskettes and
turned off your cassette recorder, the worst that can happen
from an erring POKE is that you'll have to turn the power off
and back on again. So have at it. Happy PEEKing and
POKEing.
122
Chapter Three
Listing Variables
in Use
Chapter 3 of Part 1 described the layout of the Variable Name
Table and the Variable Value Table. In particular, we read that
the Variable Name Table was built in a very simple fashion:
Each new variable name, as it is encountered upon program
entry, is simply added to the end of the list of names. The most
significant bit of the last character of the name is turned on, to
signal the end of that name. The contents of VNTP point to the
beginning of the list of names, and the content of VNTD is the
address of the byte after the end of the list.
Now, what does all that mean? What does it imply that we
can do? Briefly, it implies that we can look at BASIC'S memory
and find out what variable names are in current use. Here's a
program that will do exactly that:
32700 QQ=128:PRINT QQ,
32710 FOR Q=PEEK(130)+256*PEEK(131) TO PE
EK(132)+256*PEEK(133)-1
32720 IF PEEK(Q)<128 THEN PRINT CHR$(PEEK
(Q)) ; :NEXT Q : STOP
32730 PRINT CHR$ (PEEK(Q ) -128 ) : QQ=QQ+1 : PRI
NT QQ, :NEXT Q : STOP
Actually, this is not so much a program as it is a program
fragment. It is intended that you will type NEW, type in the
above fragment, and then LIST the fragment to a disk file (LIST
"D:LVAR") or to a cassette (LIST "C:"). Then type NEW again
and ENTER or LOAD the program whose variables you want
to list. Finally, use ENTER to re-enter the fragment from disk
(ENTER "D:LVAR") or cassette (ENTER "C:"). Then type
GOTO 32700 to obtain your Variable Name Table listing.
Of course, if you had OPENed a channel to the printer
(OPEN #1,8,0,"P:"), you could change the PRINTs to direct
the listing to the printer (PRINT #1; CHR$ ( < expression > ) ) .
123
Chapter Three
How does the fragment work? The reason for the start and
end limits for the FOR loop are simple: word location 130 ($82)
contains the pointer to the beginning of the Variable Name
Table and word location 132 ($84) contains the pointer to the
end of that same table, plus 1. So we simply traipse through
that table, printing characters as we encounter them — except
that when we encounter a character with its most significant bit
on (IF PEEK(Q) > 127), we turn off that bit before printing it and
start the next name on a new line.
Notice that we use the variable QQ to allow us to print out
the token value for each variable name. We will use this
information in some later chapters.
Also note that the variable names QQ and Q will appear in
your variable name listing. Sorry. We can write a program
which would accomplish the same thing without using
variables, but it would be two or three times as big and much
harder to understand. Of course, if you consistently use certain
variable names, such as J and / in FOR-NEXT loops, you could
use those names here instead, thus not affecting the count of
variables in use.
Incidentally, the STOP at the end of the third line should be
unnecessary, since the table is supposed to end with a
character with its upper bit on. But I've learned not to take
chances — things don't always go as they're supposed to.
124
■■■w Chapter Four
Variable
Values
In this chapter, we will show how you can determine the value
of any variable by inspecting the Variable Value Table. Actually,
in many respects this is a waste of effort. After all, if I need to
know the value of the variable TOTAL, I can just type PRINT
TOTAL.
But this book is supposed to be a guide, and there are a few
uses for this information, particularly in assembly language
subroutines, and it is instructive in that it gives us an inkling of
what BASIC goes through to evaluate a variable reference.
It will probably be better to present the program first, and
then explain what it does. Before doing so, though, note that
the program fragment expects you to give it a valid variable
token (128 through 255). No checks are made on the validity of
that number, since we are all intelligent humans here and since
we want to save program space. Enough. The program:
32500 PRINT : PRINT "WHAT VARIABLE NUMBER
" ; : INPUT Q
32505 Q=PEEK(134)+256*PEEK(135)+(Q-128)*
8
32510 PRINT : PRINT "VARIABLE NUMBER " ; PE
EK(Q+1),
32515 ON INT(PEEK(Q)/64) GOTO 32600,3265
32520 PRINT "IS A NUMBER, ": PRINT , "VALU
E ";
32525 QEXP=PEEK(Q+2) : IF QEXP>127 THEN PR
INT " - " ; : QEXP=QEXP- 1 2 8
32 530 QNUM=0:FOR QQ=Q+3 TO Q+7
32535 QNUM=QNUM* 1 00+PEEK ( QQ ) -6 * INT ( PEEK (
QQ)/16):NEXT QQ
32540 QEXP=QEXP-68: IF QEXP=0 THEN 32555
32545 FOR QQ=QEXP TO SGN(QEXP) STEP -SGN
(QEXP)
125
Chapter Four
32 550 QNUM=(QEXP>0)*QNUM*100+(QEXP<0)*QN
UM/ 100: NEXT QQ
32555 PRINT QNUM:PRINT :GOTO 32500
32570 IF PEEK(Q)/2<>INT(PEEK(Q)/2) THEN
32580
32575 PRINT , "AND IS NOT YET DIMENSIONED
": POP: GOTO 32500
32580 PRINT /'ADDRESS IS " ; PEEK(Q+2 ) +256
*PEEK ( Q+3 ) : RETURN
32600 PRINT "IS AN ARRAY, ":GOSUB 32570
32610 PRINT , "DIM 1 IS " ; PEEK(Q+4 )+256*P
EEK(Q+5)
32615 PRINT , "DIM 2 IS " ; PEEK(Q+6 ) +256*P
EEK(Q+7)
32620 GOTO 32500
32650 PRINT "IS A STRING, ":GOSUB 32570
32660 PRINT , "LENGTH IS " ; PEEK(Q+4 )+256*
PEEK(Q+5)
32665 PRINT ,"{3 SPACES}DIM IS ";PEEK(Q+
6)+256*PEEK(Q+7)
32670 GOTO 32500
Did you get lost in all of that? I got lost several times as I
wrote it, but it seems to work well. Shall we discuss it?
The first place where confusion may arise is when I ask you
to give a variable token from 128 to 255, and then reveal that
the entry in the Variable Value Table thinks variable numbers
range from to 127. Actually, there is no anomaly here. The
variable token that you input is the token value of the variable
in your program. The number in the table is its relative
position. The numbers differ only in their uppermost bit.
The program uses the number you specify to form an
address of an entry somewhere within the Variable Value
Table. It then displays the internal variable number and
examines the flag byte of the variable entry. Recall that the
uppermost bit ($80, or 128) of the flag byte is on, if this variable
is a string. The next bit ($40, or 64) is on if the variable is an
array. If neither is on, the variable is a normal floating point
number (or scalar, as it is sometimes called, to distinguish it
from a floating point array). All this is decided and acted upon
inline 32515.
126
Chapter Four
Before examining what happens if the number is a scalar,
let's look at strings and arrays. Both start out (lines 32600 and
32650) by identifying themselves and calling a subroutine
which determines if the variable has been DIMensioned yet. If
not, the subroutine tells us so, removes the GOSUB entry from
the stack, and starts the whole shebang over again. If the
variable is DIMensioned, though, we print its address before
returning. Note that the address printed is the relative address
within the String/ Array Table.
If the DIMension check subroutine returns, both string and
array variables have their vitals printed out before the program
asks you for another variable number. In the case of a string,
we see the current length (as would be obtained by the LENgth
function) and its dimension. For an array, we see both
dimensions. Note that array dimensions here are always one
greater than the user program specified, so that a zero
dimension value means "this dimension is unused."
Point of interest: this program will never print a zero for an
array dimension. Why? Because Atari BASIC never places a
zero in either dimension when the DIM statement is executed.
In a way, this is a "feature" (a feature is a documented bug). It
implies that we may code DIM XX(7) and yet use something
like PRINT XX(N,0). In other words, a singly dimensioned
array in Atari BASIC is exactly equivalent to a doubly
dimensioned array with a as the second subscript in the DIM
statement.
Back to the listing. Fairly straightforward up until now. But
look what happens if the variable is a scalar, a single floating
point number.
First, we obtain the exponent byte; if its upper bit is on, the
number is negative, so we print the minus sign before turning
the bit off.
Second, we must loop through the five bytes of the
mantissa, accumulating a value. The really strange part here is
line 32535, so let's examine it closely. As we get each byte, we
must multiply what we have gotten so far by 100 (remember,
floating point numbers are in BCD format, so each byte
represents a power of 100). Then, what we really want to do is
add in 10 times the higher digit in the byte, plus the lower
digit. We could have gotten those numbers as follows:
NEWBCDVALUE = OLDBCDVALUE*100
HIGHER = INT(PEEK(QQ)/16)
127
Chapter Four
LOWER = PEEK(QQ)-16*HIGHER
BYTEVALUE = 10*HIGHER + LOWER
NEWBCD VALUE = NEWBCD VALUE + BYTEVALUE
OLDBCDVALUE = NEWBCD VALUE
Hopefully, your algebra is up to understanding how line
32535 is just a simplification of all that. If not, don't worry
about it. It works.
But we still haven't accounted for the exponent. Now,
exponents in the Atari floating point format are powers of 100
in "excess 64" notation, which simply means that you subtract
64 from the exponent to get the real power of 100. But wait! The
implied decimal point is all the way to the left of the number.
So we must bias our "excess 64" by the five multiplies-by-100
we did in deriving the BCD value. All that is done in line 32540.
Finally, we simply count the exponent down to one or up
to minus one, depending on what it started at. And line 32545
is tricky, but not too much so. I will leave its inner workings as
an exercise for you, the reader.
And, hard though it may be to believe, we arrive at line
32555 with the number in hand. Then we PRINT it.
Did we really have to go through all that? Not really, but
perhaps it gives you an idea of what BASIC'S GETTOK routine
($AB3E) does when it encounters a variable name.
Finally, to test all this out, you should type it in, LIST it to
disk or cassette, use NEW, and then enter or load your favorite
program. Finally, re-ENTER this program fragment from disk
or cassette and type GOTO 32500. Just for fun, you might try
finding the variable values for the following program:
10 A = 12.34567890 : B = 9876543210
20 C = 0.0000556677
30 GOTO 60
40 D$ = "WILL NEVER BE EXECUTED"
50 E(7) = 1
60 DIM F$(30), G$(40), H(9,17), J(7)
70 G$="ONLY THIS STRING WILL HAVE LENGTH"
Type this little guy in, ENTER the variable value printer,
and RUN the whole thing. Answer the variable number
prompt with numbers from 128 to 135 and see what you get.
It's interesting!
128
Chapter Five
Examining the
Statement Table
If you will recall, Chapter 3 in Part 1 discussed the various user
tables that existed in Atari BASIC'S RAM memory space.
Specifically, it discussed the Variable Name Table, Variable
Value Table, Statement Table, String/ Array Table, and Runtime
Stack.
In the last two chapters, we investigated the Variable Name
Table and the Variable Value Table, showing how Atari BASIC
can examine itself. So what is more logical than to now use
Atari BASIC to display the contents of the Statement Table?
While we could write a program that would examine the
tokenized program and produce source text, there is little
incentive to do so. The task would be both very difficult and
very redundant: BASIC'S LIST command performs the same
task very nicely, thank you.
What we can do, though, is write a program which will
show the actual hex tokens used in a logical and almost
readable form. Again, let's look at the program before
decoding what it does.
10 DIM NUM$(4)
40 DIM DEC$(16) :DEC$="0123456789ABCDEF"
50 CVDEC=9100
100 GOTO 32000
110 ERROR- THIS IS AN ERROR LINE
120 DATA AND, THIS, IS, DATA, 1,2,3
130 REM LINES 110 TO 130 ARE FOR DEMONST
RATION PURPOSES ONLY
9100 REM CONVERT DECIMAL TO HEX
9110 DIV=4096
9120 FOR 1=1 TO 4
9130 N=INT(NUM/DIV) :NUM$ ( I , I )=DEC$ (N+l )
9140 NUM=NUM-DIV*N:DIV=DIV/l6
9150 NEXT I
9160 RETURN
129
Chapter Five
32000 QQ=PEEK(136)+256*PEEK(137)
32010 Q=PEEK(QQ)+256*PEEK(QQ+1) :QS=QQ:QQ
=QQ+3
32015 IF Q>32767 THEN PRINT " — END — ":ST
OP
32020 QL=PEEK(QQ-1)+QS: PRINT "LINE NUMBE
R ";Q,"LINE LENGTH ";PEEK(QQ-1)
32030 QT=PEEK(QQ+1) : PRINT "{2 SPACES }STM
T LENGTH "; PEEK (QQ) , "STMT CODE ";P
EEK(QQ+1)
32040 Q=PEEK(QQ)+QS:QQ=QQ+2
32050 IF QQ<Q THEN 32080
32060 IF Q<QL THEN PRINT : GOTO 32030
32070 PRINT :GOTO 32010
32080 IF QT>1 AND QT<55 THEN 32120
32090 PRINT "{2 SPACES }UNTOKENI ZED: :" ;
32100 PRINT CHR$(PEEK(QQ) ) ; :QQ=QQ+1:IF Q
Q<Q THEN 32100
32110 PRINT :GOTO 32010
32120 NUM=PEEK(QQ) :GOSUB CVDEC
32125 IF PEEK(QQ)>127 THEN PRINT " V=";N
UM$(3) :GOTO 32200
32130 IF PEEK(QQ)>15 THEN PRINT " ";NUM$
(3) ; :GOTO 32200
32140 IF PEEK(QQ)=14 THEN GOTO 32170
3 2150 QQ=QQ+1:QN=PEEK(QQ) :NUM=QN:GOSUB C
VDEC
32155 PRINT " S, " ;NUM$ ( 3 );"=";: IF QN=0 T
HEN 32200
32160 FOR QQ=QQ+1 TO QQ+QN-1 : PRINT CHR$ (
PEEK ( QQ ));: NEXT QQ : GOTO 32190
32170 PRINT " N=";
32180 FOR QQ=QQ+1 TO QQ+5 :NUM=PEEK(QQ ) :G
OSUB CVDEC: PRINT NUM$ ( 3 ) ; :NEXT QQ
32190 QQ=QQ-1: PRINT
32200 QQ=QQ+1:IF QQ<Q THEN 32120
32210 PRINT :IF QQ<QL THEN 32030
32220 PRINT : GOTO 32010
Now, even if you don't want to type all that in, there are a
few points to be made about it. First, note that lines 10 through
50 and 9100 through 9160 are the decimal-to-hex converter from
130
Chapter Five
Chapter 2. Then, let's start with line 32000 and do a functional
description, with the line numbers denoting the portion we are
examining.
32000. Decimal 136 is hex $88, the location of STMTAB, the
pointer to the user's program space.
32010, 32020. In each line, the first two bytes are the line
number; the next byte is the line length (actually, the offset to
next line). Remember, line 32768 is actually the direct
statement.
32030, 32040. Within a line, each statement begins with a
statement length ( the offset to the next statement from
the beginning of the line) and a statement token.
32050-32070. Boundary conditions are checked for.
32080-32110. REM becomes statement token 0, DATA is
token 1 and the error token is 55 ($37). All three of them simply
store the user's input unchanged.
32120. Remember, any token with its upper bit on
indicates a variable number token. They really don't need to be
special cased in this program, but we do so for readability.
32130. Operator tokens have values of 16 to 127 ($10 to
$7F).
32140-32160. For string constants (also called string literals),
we simply print out the string length and its contents (the
characters between the quote signs).
32170-32180. For numeric constants, we simply print the
hex values of all six bytes.
32190-32200. Clean-up. We ensure that we return for all
remaining tokens (if any) in each statement and for all
remaining statements (if any) in each line.
Observe the FOR-NEXT loop controls in line 32180. Why
QQ + 1 TO QQ + 5 if we want six values printed out? Ah, but
this is a trick. Note that the loop termination value (QQ + 5)
involves the loop variable (QQ). The problem is, though, that
the loop variable is changed by the prior implied assignment
(QQ = QQ + 1) when the assignment takes place — which is, of
course, before the determination of the value of "QQ + 5" takes
place.
In other words, by the time we are ready to evaluate
QQ + 5, the variable QQ has already been changed from its
original value to its new, loop controlling value (QQ + 1).
Quite possibly, the proper general solution to using a FOR
loop's variable in its own termination (or STEP) values is to
131
Chapter Five
assign it to a temporary variable, thusly:
QTEMP = QQ : FOR QQ = QTEMP + 1 TO QTEMP + 6
Did you notice that line 32160 actually has the same
problem? Notice that we solved it there by adding -1 to the
termination value to compensate for the + 1 in the initialization
assignment.
One last comment before leaving the subject of strange
FOR-NEXT loops. In Atari BASIC (and, indeed, in virtually all
microcomputer BASICs), the termination (TO) value and the
STEP value are determined when the FOR statement is first
executed and are NOT changeable. Example:
10 X=7:Y=2
20 FOR I = 1 TO X STEP Y
30 X = X+l
40 Y = Y+X
50 NEXT I
This FOR loop will execute exactly four times (I = 1, 3, 5,
and 7). The fact that X and Y change within the loop has no
effect on the actual loop execution.
132
Chapter Six
Viewing the
Runtime Stack
The Runtime Stack is the last of the user RAM tables that we
will discuss in Part 2.
Perhaps you noticed that we left out a discussion of the
String/ Array Table in Part 2. The omission was on purpose:
there seems little purpose in PEEKing the contents of this table
when BASIC'S PRINT statement does an admirable job of
letting you see all variable values. However, if you are so
inclined, you could use the general purpose memory PEEKer
program of Chapter 2 to view any portion of any memory,
including the String/ Array Table.
On the other hand, looking at the Runtime Stack is kind of
fun and enlightening. And the program we will present here
might even find use on occasion. If you are having trouble
tracing a program's flow, through various GOSUBs and/or
FOR loops, simply drop in the routine below and GOSUB to it
at an appropriate place in your program. It will print out a LIFO
(Last In, First Out) listing of all active GOSUB calls and FOR-
NEXT loop beginnings.
10 FOR J=l TO 3
20 GOSUB 30
30 FOR K=l TO 5
40 GOSUB 50
50 JUNK=7:FOR Q=l TO 2: GOSUB 32400
32400 QQ=PEEK(144)+256*PEEK(145)
32410 IF QQ<=PEEK(142)+256*PEEK(143) THE
N PRINT " — END OF STACK — " : STOP
32420 PRINT "AT LINE " ; PEEK(QQ-3 ) +256*PE
EK(QQ-2);
32430 PRINT ", OFFSET " ; PEEK (QQ-1 ) ;
32440 IF PEEK(QQ-4)=0 THEN PRINT ", GOSU
B" :QQ=QQ-4:GOTO 32410
32450 PRINT ", FOR (#"; PEEK(QQ-4 );")": QQ
=QQ-16:GOTO 32410
133
Chapter Six
The first thing you might notice about this little routine is
that, in contrast to all the programs we have used so far, it
examines its portion of user RAM backward. That is, it starts
at the top (high address) of the Runtime Stack area and works
downward toward the bottom.
Again, nothing surprising. If you will recall the description
of entries on this stack (pages 18-19 and 133-34), you will
remember that every entry, whether a GOSUB or FOR, has a
four-byte header. And, while FOR statements also have twelve
bytes of termination and step value added, the four bytes are
always at the top of each entry — they are the last items put on
the stack.
Thus, we start at the top of the stack and examine four
bytes. If the type byte is zero, it is a GOSUB entry, and all we
must do is display the line number and statement offset. If we
remove the four-byte header by subtracting 4 from our stack
pointer, we are ready to examine the next entry.
In the case of a FOR entry, we similarly display the line
number and statement offset. However, each FOR entry also
has a variable token associated with it, so we also display that
token's value. With the variable name lister of Chapter 2, you
can find out which variable is controlling this FOR loop.
Finally, note that after displaying a FOR loop entry, we remove
sixteen bytes (the four-byte header and the two six-byte
floating point values) in preparation for the next entry.
Incidentally, lines 10 through 50 are present as examples
only. Add lines 32400 to 32450 to your own programs and see
where you've come from.
134
Chapter Seven
Fixed Tokens
In the last chapter, we discussed the last of the tables in user
RAM. Now we will see how and where BASIC stores its
internal ROM-based tables.
As we noted in Chapter 5 of Part 1 (and viewed via the
listing program of Chapter 5 in this Part), there are four kinds
of tokens in an Atari BASIC program: (1) statement name
tokens, (2) operator tokens, (3) variable tokens, and (4)
constant tokens (string and numeric constants). Also, we
learned in Part 1 how the tokenizing process works, converting
the user's ATASCII source code into tokens. What we didn't
learn, though, was exactly what token replaces what BASIC
keyword.
In this chapter, we present a program which will list all of
the fixed tokens (those in ROM). Actually, the program
presents three listings, each consisting of a list of token values
with their associated ATASCII strings. But wait a moment!
Three listings? There are only two ROM-based tables — SNTAB
andOPNTAB.
Yes, but it seems that this program is also capable of listing
the Variable Name Table. Why list it again, when we did it so
well in Chapter 3? Because we wanted to show you how BASIC
itself does it. In many ways, this program emulates the
functions of the SEARCH routine at address $A462 in the
source listing. And, yes, BASIC uses a single routine to search
all three of these same tables. You might want to examine
BASIC'S SEARCH routine at the same time you peruse this
listing.
100 REM we make use of the general purpose
110 REM token lister three times:
200 PRINT : PRINT "A LIST OF VARIABLE TOKENS"
210 ADDR=PEEK(130)+256*PEEK(131)
220 SKIP=0:TOKEN=128:GOSUB 1000
300 PRINT : PRINT "A LIST OF STATEMENT TOKENS"
310 ADDR=42159:SKIP=2:TOKEN=0:GOSUB 1000
400 PRINT : PRINT "A LIST OF OPERATOR TOKENS"
410 ADDR=42979:SKIP=0:TOKEN=16:GOSUB 1000
420 STOP
1000 REM a general purpose token listing routine
135
Chapter Seven
1001 REM
1002 REM On entry to this routine, the following
1003 REM variables have meanings:
1004 REM ADDR = address of beginning of table
1005 REM SKIP = bytes per entry to skip
1006 REM TOKEN = starting token number
1007 REM
1100 ADDR=ADDR+SKIP: IF PEEK(ADDR)=0 THEN RETURN
1110 PRINT TOKEN, :T0KEN=T0KEN+1
1120 IF PEEK(ADDR)>127 THEN 1140
1130 PRINT CHR$( PEEK (ADDR) ) ; : ADDR=ADDR+1 : GOTO 1120
1140 PRINT CHR$ ( PEEK ( ADDR )-l 28 ) : ADDR=ADDR+1 : GOTO 1100
The main routine is actually lines 1100 through 1140 (while
lines 1000 through 1007 simply explain it all). It's actually fairly
simple. Each table is assumed to consist of a fixed number of
bytes followed by a variable number of ATASCII bytes, the last
of which has its upper bit on.
In line 1100, we skip over the fixed bytes (if any) and check
for the end of the table. After that, we simply print the token
value followed by the name.
Worth examining, though, are lines 200 through 420,
where we call the main subroutine. First, note that the Variable
Name Table has no bytes to skip and is located via its zero-page
pointer. Naturally, the first variable token value is 128.
Each entry in the Statement Name Table (SNTAB, at
location $A4AF) has two leading bytes (actually, the two-byte
address, minus 1, of the syntax table entry for this statement).
Statement name token values begin at zero, and 42159 is the
decimal address of SNTAB.
Finally, the smallest-numbered operator token is 16
decimal (except for string and numeric constants, which are
special cased). There are no leading bytes in the Operator
Name Table, and it starts at location 42979 decimal (OPNTAB,
at$A7E3).
136
Chapter Eight
What Takes
Precedence?
There was one other ROM-based table mentioned in Part 1
which deserves some attention here. You may recall that when
an expression is executed, the execution operators are given
particular precedences, so that in BASIC, 2 + 3*4 equals 14, not
20 . Chapter 7 of Part 1 does a particularly thorough job of
explaining the concepts of precedence.
The program presented in this chapter prints out all of
BASIC'S operator tokens along with their token values and
their dual precedence values. Actually, the program provides a
visual readout of OPRTAB (Operator PRecedence TABle, at
$AC3F).
In each pair of precedence values listed, the first number is
the go-onto-stack value and the second is the come-off-stack
value.
100 PRINT "A LIST OF OPERATOR TOKENS"
110 PRINT " WITH THEIR PRECEDENCE TABLE VALUES"
220 SKIP=0:TOKEN=128:GOSUB 1000
1000 ADDR=42979:REM WHERE OP NAMES START
1010 TOKEN=16:REM LOWEST TOKEN VALUE
1020 REM NOW THE MAIN CODE LOOP
1100 IF PEEK(ADDR)=0 THEN STOP
1110 PRINT TOKEN, : PREC=PEEK( 44095+TOKEN-16 )
1120 PRINT INT(PREC/16) ; ": " ; PREC-16*INT (PREC/16 ) ,
1130 PREC=PEEK(ADDR) :ADDR=ADDR+1
1140 IF PREC<128 THEN PRINT CHR$ ( PREC) ; : GOTO 1130
1150 PRINT CHR$(PREC-128) :TOKEN=TOKEN+l : GOTO 1100
If you closely examined the program in the last chapter,
you will note a striking similarity to this program, especially
lines 1100 through 1150. Actually, the only thing we have really
added is the precedence printout of line 1120.
And note the form of the PEEK in line 1110. Then look at
the line of code at address $AAF1 in the BASIC listing. Given
137
Chapter Eight
the limitations of dissimilar languages, the code is identical.
This is more evidence that you really can use BASIC as a tool to
diagnose itself.
138
Chapter Nine
Using What
We Know
Now that Atari BASIC stands revealed before you, what do
you do with it? Many authors have, even without benefit of the
listing in this book, either used or fooled BASIC in ways that
we who designed it never dreamed of.
For example, consider what happens if you change
BASIC'S STARP pointer ($8C) to be equal to its ENDSTAR
value ($8E). Remember, BASIC'S SAVE command saves
everything from the contents of VNTP to the contents of
STARP (as documented in Chapter 10 of Part 1). So changing
what is in STARP is tantamount to telling BASIC to SAVE more
(or less) than what it normally would. Presto! We can now save
the entire array and string space to disk or tape, also.
Is it useful? Here's one program that is, using the concepts
we learned in the previous chapters.
30000 PRINT : PRINT "WHAT VARIABLE NUMBER
DO YOU": PRINT, "WISH TO FIND
30010 INPUT QV
30020 QA=PEEK(130)+256*PEEK(131 ) :QN=128
30030 IF QN=QV THEN 30060
30040 IF PEEK ( QA )< 128 THEN QA=QA+l:GOTO
30040
30050 QN=QN+l:QA=QA+l:GOTO 30030
30060 IF PEEK(QA)<128 THEN PRINT CHR$(PE
EK(QA) ) ; :QA=QA+l:GOTO 30060
30070 PRINT CHR$(PEEK(QA)-128) ; " IS THE
VARIABLE"
30100 QA=PEEK(136)+256*PEEK(137)
30110 QN=PEEK(QA)+256*PEEK(QA+1) :QL=PEEK
( QA+2 ) : QSV=QA : QA=QA+3
30120 IF QN>32767 THEN PRINT " — END — ":E
ND
30130 QS=PEEK(QA) : QT=PEEK(QA+1 ) :QA=QA+2:
IF QT>1 AND QT<55 THEN 30150
139
Chapter Nine
30140 QA=QSV+QL : GOTO 30110
30150 IF PEEK(QA)=QV THEN PRINT "LINE
QN:GOTO 30140
30160 IF PEEK(QA)>15 THEN 30200
30170 IF PEEK (QA) =14 THEN QA=QA+6:GOTO 3
0200
30180 QA=QA+PEEK(QA+1)+1
30200 QA=QA+1:IF QA<QSV+QS THEN 30150
30210 IF QA<QSV+QL THEN 30130
30220 GOTO 30110
What does it do? It finds all the places in your program that
you used a particular variable. And how do you use it? Type it
in, LIST it to disk or cassette, and clear the user memory via
NEW. Now type, ENTER, or LOAD the program you wish to
investigate (and then SAVE it, if you haven't already done so).
Finally, ENTER this program fragment from the disk or cassette
where you LISTed it and type GOTO 30000.
Although the program asks you for a variable number
(which you can get via the program of Chapter 3), it doesn't
really matter if you don't know it. The program will print your
chosen variable's name before giving all the references. If you
chose wrong, try again.
And how does it work? Somewhat like the program token
lister of Chapter 5, except that here we are simply skipping
everything but variable name references. First, though, we use
a modified Variable Name Table lister (lines 30020 through
30070) to tell you what name you chose.
Then, we start at the beginning of the program (line 30100)
and check each user line number (30110 and 30120). Within
each line, we loop through, checking all statements (30130),
skipping entirely all REMs, DATA lines, and lines with syntax
errors (line 30140). If we find ourselves in an expression, we
check for a matching variable token reference (line 30150) and
print it if found, after which we skip the rest of the line. We also
skip over numeric and string constants (lines 30170 and 30180).
Finally, we check to see if we are at the end of the statement
(30200) or the end of a line (30210 and 30220).
This is a fairly large program fragment, and it will prove
most useful in very large programs, where you can't
remember, for example, how many places you are using the
variable name LOOP. So you might want to try to leave room
in memory for this aid; you may be very glad you did.
140
Part Three
Atari BASIC
Source Code
Copyright © 1978, 1979, 1983
Optimized Systems Software
Cupertino, CA
Printed in the United States of America
This program may not be reproduced, stored in a retrieval system, or transmitted in
whole or in part, in any form, or by any means, be it electronic, mechanical, photo-
copying, recording, or otherwise without the prior written permission of
Optimized Systems Software, Inc.
10379 Lansdale Avenue
Cupertino, California 95014 (U.S.A.)
Telephone: (408) 446-3099
142
Source Code
Some Miscellaneous Equates
0001
PATSIZ
EQU
SI
0020
ZICB
EQU
520
0080
ZPG1
EQU
$80
0480
MISCR1
EQU
5480
0500
MISCRAM
EQU
5500
E456
CIO
EQU
SE456
0340
IOCBORG
EQU
5340
0300
DCBORG
EQU
5300
A000
ROM
EQU
5A000
00D2
ZFP
EQU
5D2
EQU
59B
PATCH AREA SIZE
zero PagelOCB
beginning of BASIC'S zero page
syntax stack, etc.
other RAM usage
in OS ROMs
where IOCBs start
where DCB (for SIO) is
begin code here
begin fltg point work area
ATASCII end of line
02E7
LMADR
EQU
52E7
02E5
HMADR
EQU
52E5
02E5
HIMEM
EQU
HMADR
D800
FPORG
EQU
5D800
0011
BRKBYT
EQU
511
0008
WARMFL
EQU
$08
D20A
RNDLOC
EQU
5D20A
BFF9
CRTGI
EQU
SBFFC-3
005D
EPCHAR
EQU
55D
E471
BYELOC
EQU
5E471
000A
DOSLOC
EQU
50A
0055
SCRX
EQU
555
0054
SCRY
EQU
554
02C4
CREGS
EQU
52C4
02FB
SVCOLOR
EQU
$2FB
D208
SREG1
EQU
$D208
D200
SREG2
EQU
$D200
D201
SREG3
EQU
5D201
D20F
SKCTL
EQU
SD20F
0270
GRFBAS
EQU
5270
02FE
DSPFLG
EQU
52FE
000E
APHM
EQU
$E
system lo mem
system high mem
fltg point in OS ROMs
warmstart flag
get a random byte here
cartridge init vector
the "?" for INPUT statement
where to go for BYE
via here to exit to DOS
X AXIS
Y AXIS
COLOR REGISTER
SAVE COLOR FOR CIO
SOUND REG 1
SOUND REG 2
SOUND REG 3
sound control
1ST GRAPHICS FUNCTION ADDR
ATARI DISPLAY FLAG
APPLICATION HIGH MEM
Zero Page
RAM Table Pointers
0000
a
0080
ORG
ZPG1
0080
LOMEM
0080
ARGOPS
0080
ARGSTK
0080
=
0002
OUTBUFF
DS
2
0082
=
0002
VNTP
DS
2
0084
=
0002
VNTD
DS
2
0086
=
0002
WTP
DS
2
0088
ENDWT
0088
=
0002
STMTAB
DS
2
008A
=
0002
STMCUR
DS
2
008C
=
0002
STARP
DS
2
008E
ENDSTAR
008E
■
0002
RUNSTK
DS
2
0090
TOPRSTK
0090
=
0002
MEMTOP
DS
2
0092
K
0001
MEOLFLG
DS
1
0093
=
0001
DS
1
LOW MEMORY POINTER
ARGUMENT/OPERATOR STACK
SYNTAX OUTPUT BUFFER
VARIABLE NAME TABLE POINTER
VARIABLE NAME TABLE DUMMY END
VARIABLE VALUE TABLE POINTER
END VARIABLE VALUE TABLE
STATEMENT TABLE [PROGRAM] ;
POINTER
CURRENT PGM PTR
STRING/ARRAY TABLE POINTER
END STRING/ARRAY SPACE
RUN TIME STACK
END RUN TIME STACK
TOP OF USED MEMORY
MODIFIED EOL FLAG
: : SPARE: :
143
Source Code
Miscellaneous Zero Page RAM
0094
0001
COX
DS
1
0095
POKADR
0095
=
0002
SRCADR
DS
2
0097
INDEX2
0097
=
0002
SVESA
DS
2
0099
=
0002
MVFA
DS
2
009B
=
0002
MVTA
DS
2
009D
CPC
009D
=
0002
WWTPT
DS
2
009F
MAXCIX
009P
=
0001
LLNGTH
DS
1
00A0
-
0002
TSLNUM
DS
2
00A2
=
0002
MVLNG
DS
2
00A4
=
0002
ECSIZE
DS
2
00A6
=
0001
DIRFLG
DS
1
00A7
STMLBD
00A7
=
0001
NXTSTD
DS
1
00A8
STMSTRT
00A8
=
0001
STINDEX
DS
1
00A9
STKLVL
00A9
IBUFFX
00A9
=
0001
OPSTKX
DS
1
00AA
ARS LVL
00AA
SRCSKP
00AA
=
0001
ARSTKX
DS
1
00AB
TSCOX
00AB
=
0001
EXSVOP
DS
1
00AC
TVSCIX
00AC
m
0001
EXSVPR
DS
1
00AD
SWNTP
00AD
=
0002
LELNUM
DS
2
00AF
ATEMP
00AF
STENUM
00AF
=
0001
SCANT
DS
1
00B0
SVONTC
00B0
=
0001
COMCNT
DS
1
00B1
SVWTE
00B1
=
0001
ADFLAG
DS
1
00B2
SVONTL
00B2
=
0001
SVDISP
DS
1
00B3
ONLOOP
00B3
SVONTX
00B3
=
0001
SAVDEX
DS
1
00B4
=
0001
ENTDTD
DS
1
00B5
=
0001
LISTDTD
DS
1
00B6
=
0001
DATAD
DS
1
00B7
=
0002
DATALN
DS
2
00B9
=
0001
ERRNUM
DS
1
00BA
=
0002
STOPLN
DS
2
00BC
B
0002
TRAPLN
DS
2
00BE
=
0002
SAVCUR
DS
2
00C0
=
0001
IOCMD
DS
1
00C1
=
0001
IODVC
DS
1
00C2
=
0001
PROMPT
DS
1
00C3
-
0001
ERRSAV
DS
1
00C4
=
0002
TEMPA
DS
2
00C6
=!
0002
ZTEMP2
DS
2
00C8
=
0001
COLOR
DS
1
00C9
=
0001
PTABW
DS
1
00CA
=
0001
LOADFLG
DS
1
USED FOR FREQUENTLY USED VALUES
TO DECREASE ROM SIZE AND INCREASE
EXECUTION SPEED. ALSO USED FOR VARIOUS
INDIRECT ADDRESS POINTERS.
CURRENT OUTPUT INDEX
POKE ADDRESS
SEARCH ADR
ARRAY INDEX 2
SAVE EXPAND START ADR
MOVE FROM ADR
MOVE TO ADR
CUR SYNTAX PGM COUNTER
WORKING VAR TABLE PTR VALUE
MAX SYNTAX CIX
LINE LENGTH
TEST LINE NO
MOVE LENGTH
MOVE SIZE
DIRECT EXECUTE FLAG
STMT LENGTH BYTE DISPL
NEXT STMT DISPL
STMT START CIX
CURR STMT INDEX
SYNTAX STACK LEVEL
INPUT BUFFER INDEX
OPERATOR STACK INDEX
SEARCH SKIP FACTOR
ARG STACK INDEX
TSCOW LENGTH BYTE PTR
SAVED OPERATOR
SAVE CIX FOR TVAT
SAVED OPERATOR PRECEDENCE
SAVE VAR NAME TBL PTR
LIST END LINE I
TEMP FOR ARRAYS
SEARCH TABLE ENTRY NUMBER
LIST SCAN COUNTER
SAVE ONT SRC CODE
COMMA COUNT FOR EXEXOR
SAVE VAR VALUE EXP SIZE
ASSIGN/DIM FLAG
SAVE ONT SRC ARG LEN
DISPL INTO LINE OF FOR/GOSUB
TOKEN
LOOP CONTROL FOR OP
SAVE ONT SRC INDEX
SAVE INDEX INTO STMT
ENTER DEVICE TB
LIST DEVICE TBL
DATA DISPL
DATA LINNO
ERROR #
LINE # STOPPED AR [FOR CON]
TRAP LINE # [FOR ERROR]
SAVE CURRENT LINE ADDR
I/O COMMAND
I/O DEVICE
PROMPT CHAR
ERROR # FOR USER
TEMP ADDR CELL
TEMP
SET COLOR FOR BASE
PRINT TAB WIDTH
LOAD IN PROGRESS FLAG
144
Source Code
Argument Work Area (AWA)
Floating Point Work Area
00CB
=
00D2
ORG
ZFP
00D2
TVTYPE
; VARIABLE TYPE
00D2
m
0001
VTYPE
DS
1
; VARIABLE TYPE
00D3
TVNUM
; VARIABLE NUMBER
00D3
=
0001
VNUM
DS
1
J VARIABLE NUMBER
=
0006
FPREC
EQU
6
=
0005
FMPREC
EQU
FPREC-1
; LENGTH OF FLOATING POINT
; MANTISSA
00D4
BININT
; FP
REGO
00D4
=
0001
FR0
DS
1
; FP
REG0
00D5
=
0005
FR0M
DS
FPREC-1
; FP
REG0 MANTISSA
00DA
=
0006
FRE
DS
FPREC
I FP
REG0 EXP
00E0
=
0001
FR1
DS
1
; FP
REG 1
00E1
=
0005
FR1M
DS
FPREC-1
; FP
REG1 MANTISSA
00E6
=
0006
FR2
DS
FPREC
| FP
REG 2
00EC
=
0001
FRX
DS
1
; FP
SPARE
RAM for ASCII to Floating Point Conversion
00ED
= 0001
EEXP
DS
1
00EE
FRSIGN
00EE
= 0001
NSIGN
DS
1
00EF
SQRCNT
00EF
PLYCNT
00EF
= 0001
ESIGN
DS
1
00F0
SGNFLG
00F0
= 0001
FCHRFLG
DS
1
00F1
XFMFLG
00F1
= 0001
DIGRT
DS
1
Input Buffer Controls
00F2 = 0001
00F3 = 0002
Temps
00F5 = 0002
00F7 = 0002
00F9 = 0002
Miscellany
CIX
DS
1
INBUFF
DS
2
ZTEMP1
DS
2
ZTEMP4
DS
2
ZTEMP3
DS
2
00FB
DEGFLG
00FB
= 0001
RADFLG
DS
1
= 0000
RADON
EQU
= 0006
DEGON
EQU
00FC
= 0002
FLPTR
DS
2
00FE
= 0002
FPTR2
DS
2
VALUE OF E
FP SIGN
SIGN OF t
SIGN OF EXPONENT
1ST CHAR FLAG
# OF DIGITS RIGHT OF DECIMAL
CURRENT INPUT INDEX
LINE INPUT BUFFER
LOW LEVEL ZERO PageTEMPS
0=RADIANS, 6= DEGREES
INDICATE RADIANS
INDICATES DEGREES
POLYNOMIAL POINTERS
Miscellaneous Non-Zero Page RAM
; USED FOR VALUES NOT ACCESSED FREQUENTLY
0100
=
0480
ORG
MISCR1
=
0480
STACK
EQU
*
; SYNTAX STACK
0480
=
0001
SIX
DS
1
; INPUT INDEX
0481
=
0001
SOX
DS
1
,- OUTPUT INDEX
0482
=
0002
SPC
DS
2
; PGM COUNTER
0484
=
057E
ORG
STACK+254
057E
m
0001
LBPR1
DS
1
; LBUFF PREFIX
1
057F
=s
0001
LBPR2
DS
1
; BLUFF PREFIX
2
0580
=
0080
LBUFF
DS
128
; LINE BUFFER
145
Source Code
0600
= 05E0
ORG
LBUFF+$60
05E0
= 0006
PLYARG
DS
FPREC
05E6
= 0006
PPSCR
DS
FPREC
05EC
= 0006
FPSCR1
DS
FPREC
= 05E6
FSCR
EQU
FPSCR
= 05EC
FSCR1
EQU
FPSCR1
lOCBArea
05F2
= 0340
ORG
IOCBORG
IOCB — I/O Control Block
THERE ARE 8 1/0 CONTROL BLOCKS
1 IOCB IS REQUIRED FOR EACH
CURRENTLY OPEN DEVICE OR FILE.
0340
IOCB
0340
=
0001
ICHID
DS
1 ;
DEVICE HANDLER ID
0341
=
0001
ICDNO
DS
1 ;
DEVICE NUMBER
0342
=
0001
ICCOM
DS
1 ;
I/O COMMAND
0343
=
0001
ICSTA
DS
1
I/O STATUS
0344
=
0001
ICBAL
DS
1
0345
s=
0001
ICBAH
DS
1
BUFFER ADR [H,L]
0346
=
0002
ICPUT
DS
2 ;
PUT A BYTE VIA THIS
0348
=
0001
ICBLL
DS
1
0349
o
0001
ICBLH
DS
1 ;
BUFFER LENGTH [H,L]
034A
=
0001
ICAUX1
DS
1
AUXILIARY 1
034B
=
0001
ICAUX2
DS
1
AUXILIARY 2
034C
=
0001
ICAUX3
DS
1
AUXILIARY 3
034D
■
0001
ICAUX4
DS
1 ,-
AUXILIARY 4
034E
=
0001
ICAUX5
DS
1
AUXILIARY 5
034F
=
0001
DS
1
SPARE
=
0010
ICLEN
EQU
*-IOCB
0350
=
0070
DS
ICLEN*7
SPACE FOR 7 MORE IOCBS
ICCOM Value Equates
=
0001
ICOIN
EQU
$01
OPEN INPUT
=
0002
ICOOUT
EQU
$02
OPEN OUTPUT
=
0003
ICOIO
EQU
$03
OPEN UN/OUT
=
0004
ICGBR
EQU
$04
GET BINARY RECORD
=
0005
ICGTR
EQU
$05
GET TEXT RECORDS
=
0006
ICGBC
EQU
$06
GET BINARY CHAR
=
0007
ICGTC
EQU
$07
GET TEXT CHAR
=
0008
ICPBR
EQU
?08
PUT BINARY RECORD
=
0009
ICPTR
EQU
$09
PUT TEXT RECORD
=
000A
ICPBC
EQU
$0A
PUT BINARY CHAR
=
000B
ICPTC
EQU
$0B
PUT TEXT CHAR
=
000C
ICCLOSE
EQU
$0C
CLOSE FILE
=
000D
ICSTAT
EQU
$0D
GET STATUS
=
000E
ICDDC
EQU
$0E
DEVICE DEPENDENT
=
000E
ICMAX
EQU
$0E
MAX VALUE
8
00FF
ICFREE
EQU
$FF
IOCB FREE INDICATOR
=
001C
ICGR
EQU
$1C
OPEN GRAPHICS
=
0011
ICDRAW
EQU
$11
DRAW TO
ICSTA
Value Equates
0001
ICSOK
EQU
$01
; STATUS GOOD, NO ERRORS
0002
ICSTR
EQU
$02
; TRUNCATED RECORD
0003
ICSEOF
EQU
$03
; END OF FILE
0080
ICSBRK
EQU
$80
; BREAK KEY ABORT
0081
ICSDNR
EQU
$81
; DEVICE NOT READY
0082
ICSNED
EQU
$82
; NON-EXISTENT DEVICE
0083
ICSDER
EQU
$83
; DATA ERROR
0084
ICSIVC
EQU
$84
; INVALID COMMAND
0085
ICSNOP
EQU
$85
; DEVICE/FILE NOT OPEN
0086
ICSIVN
EQU
$86
; INVALID IOCB NUMBER
0087
ICSWPE
EQU
$87
,- WRITE PROTECTION
146
Source Code
Equates for Variables
0000
0080
0040
0002
0001
0000
= 0002
= 0002
= 0004
= 0006
= 0002
= 0004
= 0006
= 0004
» 000C
= 0003
= 0001
= 0000
= 0006
= 0000
-IN
-ON
EVTYPE
EQU
EVSTR
EQU
$80
EVARRAY
EQU
$40
EVSDTA
EQU
$02
EVDIM
EQU
$01
EVSCALER EQU
$00
EVNUM
EQU
1
EWALUE
EQU
2
EVSADR
EQU
2
EVSLEN
EQU
4
EVSDIM
EQU
6
EVAADR
EQU
2
EVAD1
EQU
4
EVAD2
EQU
6
jn Stack
GFHEAD
EQU
4
PBODY
EQU
12
GFDISP
EQU
3
GFLNO
EQU
1
GFTYPE
EQU
FSTEP
EQU
6
FLIM
EQU
-IN VARIABLE VALUE TABLE
-ON ARGUMENT STACK
VALUE TYPE CODE
- STRING
- ARRAY
- ON IF EVSADR IS ABS ADR
ON IF HAS BEEN DIM
- SCALER
VARIABLE NUMBER [83 - FF]
SCALAR VALUE [6 BYTES]
STRING DISPL [2]
STRING LENGTH [2]
STRING DIM [2]
ARRAY DISPL [2]
ARRAY DIM 1 [2]
ARRAY DIM 2 [2]
LENGTH OF HEADER FOR FOR/GOSUB
LENGTH OF BODY OF FOR ELEMENT
DISP TO SAVED LINE DISP
DISPL TO LINE # IN HEADER
DISPL TO TYPE IN HEADER
DISPL TO STEP IN FOR ELEMENT
DISPL TO LIMIT IN FOR ELEMENT
Cold
Start
A000
A000
A5CA
A002
D004 *
A004
A508
A006
D045 *
A008
A008
A2FF
A00A
9A
A00B
D8
A00C
A00C
AEE702
A00F
ACE802
A012
8680
A014
8481
A016
A900
A018
8592
A01A
85CA
A01C
C8
A01D
8A
A01E
A282
A020
9500
A022
E8
A023
9400
A02 5
E8
A026
E092
A028
90F6 *
ROM Start
COLD START - REINIT
WIPES
COLDSTART
LDA
LOADFLG
BNE
COLD1
LDA
WARMFLG
BNE
WARMSTART
COLD1
LDX
#$FF
TXS
CLD
XNEW
LDX
LMADR
LDY
LMADR+1
STX
LOMEM
STY
LOMEM+1
LDA
#0
STA
MEOLFLG
STA
LOADFLG
I NY
TXA
LDX
#VNTP
:CS1
STA
0,X
INX
STY
0,X
INX
CPX
#MEMTOP+2
BCC
:CS1
IALIZES ALL MEMORY
OUT ANY EXISTING PROGRAM
;Y IN MIDDLE OF LOAD
;DO COLDSTART
; IF WARM START
; THEN BRANCH
| SET ENTRY STACK
; TO TOS
I CLEAR DECIMAL MODE
;LOAD LOW
;MEM VALUE
; SET LOMEM
; RESET MODIFIED
; EOL FLAG
; RESET LOAD FLAG
; ALLOW 2 56 FOR OUTBUFF
;VNTP
; GET ZPG DISPC TO VNTP
; SET TABLE ADR LOW
; SET TABLE ADR HIGH
; AT LIMIT
I BR IF NOT
A02A A286
EXPAND VNT BY ONE
147
Source Code
A02C
A001
LDY
#1
; FOR END OF VNT
A02E
207FA8
JSR
EXPLOW
; ZERO BYTE
A031
A28C
LDX
tSTARP
; EXPAND STMT TBL
A033
A003
LDY
#3
| BY 3 BYTES
A035
207FA8
JSR
EXPLOW
; GO DO IT
A038
A900
LDA
#0
; SET
A03A
A8
TAY
A03B
9184
STA
[VNTD],Y
,- INTO WTP
A03D
918A
STA
[STMCUR]
Y
; INTO STMCUR+0
A03F
C8
INY
A040
A980
LDA
#$80
I $80 INTO
A042
91 8A
STA
[STMCUR]
Y
; STMCUR+1
A044
C8
INY
A045
A903
LDA
#$03
; $03 INTO
A047
91 8A
STA
[STMCUR]
Y
; STMCUR+2
A049
A90A
LDA
#10
; SET PRINT TAB
A04B
85C9
STA
PTABW
; WIDTH TO 10
Warm Start
1 WARMSTART - BASIC
RESTART
[
DOES
NOT DESTROY CURRENT PGM
A04D
WARMSTART
A04D
20F8B8
JSR
RUNINIT
; INIT FOR RUN
A050
2041BD
SNX1JSR
CLSALL
; GO CLOSE DEVICE 1-7
A053
2072BD
SNX2JSR
SETDZ
; SET E/L DEVICE
A056
A592
LDA
MEOLFLG
; IF AN EOL INSERTED
A058
F003 "A05D
BEQ
SNX3
A05A
2099BD
JSR
RSTSEOL
; THEN UN-INSERT IT
A05D
2057BD
SNX3 JSR
PREADY
; PRINT READY MESSAGE
Syntax
A060 LOCAL
Editor — Get Lines of Input
A060
A5CA
A062
D09C "A000
A064
A2FF
A066
9A
A067
2051DA
A06A
A95D
A06C
85C2
A06E
2092BA
A071
20F4A9
A074
D0EA "A060
A076
A900
A078
85F2
A07A
859F
A07C
8594
A07E
85A6
A080
85B3
A082
85B0
A084
85B1
A086
A584
A088
85AD
A08A
A585
A08C
85AE
A08E
20A1DB
A091
209FA1
A094
20C8A2
A097
A5D5
A099
1002 "A09D
A09B
85Ab
SYNTAX
LDA
LOADFLG
BNE
COLDSTART
LDX
#$FF
TXS
JSR
INTLBF
LDA
#EPCHAR
STA
PROMPT
JSR
GLGO
JSR
TSTBRK
BNE
SYNTAX
LDA
#0
STA
CIX
STA
MAXCIX
STA
COX
STA
DIRFLG
STA
SVONTX
STA
SVONTC
STA
SVWTE
LDA
VNTD
STA
SWNTP
LDA
VNTD+1
STA
SWNTP+1
JSR
SKBLANK
JSR
:GETLNUM
JSR
iSETCODE
LDA
BININT+1
BPL
:SYN0
STA
DiRFLG
IF LOAD IN PROGRESS
GO DO COLDSTART
RESTORE STACK
GO INT LBUFF
; TEST BREAK
; BR IF BREAK
; INIT CURRENT
; INPUT INDEX TO ZERO
I OUTPUT INDEX TO ZERO
;SET DIRECT SMT
; SET SAVE ONT CIX
J VALUE IN CASE
; OF SYNTAX ERROR
SKIP BLANKS
CONVERT AND PUT IN BUFFER
SET DUMMY FOR LINE LENGTH
148
Source Code
A09D
:SYN0
A09D
20A1DB
JSR
SKBLANKS
SKIP BLANKS
A0A0
A4F2
LDY
CIX
GET INDEX
A0A2
84A8
STY
STMSTRT
SAVE INCASE OF SYNTAX ERROR
A0A4
B1F3
LDA
[INBUFF],
Y
GET NEXT CHAR
A0A6
C99B
CMP
#CR
IS IT CR
A0A8
D007 "A0B1
BNE
:SYN1
BR NOT CR
A0AA
24A6
BIT
DIRFLG
IF NO LINE NO.
ABAC
30B2 "A060
BMI
SYNTAX
THEN NO. DELETE
A0AE
4C89A1
JMP
:SDEL
GO DELETE STMT
A0B1
:SYN1
A0B1
:XIF
A0B1
A594
LDA
COX
SAVE COX
A0B3
85A7
STA
STMLBD
AS PM TO STMT LENTGH BYTE
ABB 5
20C8A2
JSR
:SETCODE
DUMMY FOR STMT LENGTH
A0B8
20A1DB
JSR
SKBLANK
GO SKIP BLANKS
A0BB
A9A4
LDA
#SNTAB/256
SET UP FOR STMT
A0BD
A0AF
LDY
#SNTAB&255
NAME SEARCH
A0BF
A202
LDX
#2
A0C1
2062A4
JSR
SEARCH
AND DO IT
A0C4
86F2
STX
CIX
A0C6
A5AF
LDA
STENUM
GET STMT NUMBER
A0C8
20C8A2
JSR
:SETCODE
GO SET CODE
A0CB
20A1DB
JSR
SKBLANK
A0CE
20C3A1
JSR
: SYNENT
•AND GO SYNTAX HIM
A0D1
9035 "A108
BCC
:SYNOK
•BR IF OK SYNTAX
■ELSE SYNTAX ERROR
A0D3
A49F
LDY
MAXCIX
• GET MAXCIX
A0D5
B1F3
LDA
[INBUFF]
Y
• LOAD MAXCIX CHAR
A0D7
C99B
CMP
#CR
■ WAS IT CR
A0D9
D006 "A0E1
BNE
:SYN3A
BR IF NOT CR
A0DB
C8
INY
■ MOVE CR RIGHT ONE
A0DC
91F3
STA
[INBUFF]
Y
A0DE
88
DEY
■ THEN PUT A
A0DP
A920
LDA
#$20
BLANK IN IT'S PLACE
A0E1
0980
:SYN3A
ORA #$80
SET MAXCIX CHAR
A0E3
91F3
STA
[INBUFF]
Y
• TO FLASH
A0E5
A940
LDA
#$40
• INDICATE SYNTAX ERROR
A0E7
05A6
ORA
DIRFLG
A0E9
85A6
STA
DIRFLG
- IN DIRFLG
A0EB
A4A8
LDY
STMSTRT
■RESTORE STMT START
A0ED
84F2
STY
CIX
A0EF
A203
LDX
#3
-SET FOR FIRST STMT
A0F1
86A7
STX
STMLBD
A0F3
E8
INX
■ INC TO CODE
A0F4
8694
STX
COX
•AND SET COX
A0F6
A937
LDA
#CERR
■ GARBAGE CODE
A0F8
20C8A2
:SYN3
JSR :SETCODE
■GO SET CODE
A0FB
: XDATA
A0FB
A4F2
LDY
CIX
•GET INDEX
A0FD
B1F3
LDA
[INBUFF]
Y
•GET INDEX CHAR
A0FF
E6F2
INC
CIX
• I NC TO NXT
A101
C99B
CMP
#CR
■IS IT CR
A103
D0F3 "A0F8
BNE
:SYN3
•BR IF NOT
A105
20C8A2
JSR
:SETCODE
A108
A594
:SYNOK
LDA COX
• GET DISPL TO END OF STMT
A10A
A4A7
LDY
STMLBD
A10C
9180
STA
[OUTBUFF], Y
;SET LENGTH BYTE
A10E
A4F2
LDY
CIX
■GET INPUT DISPL
A110
88
DEY
Alll
B1F3
LDA
[INBUFF]
Y
•GET LAST CHAR
A113
C99B
CMP
#CR
-IS IT CR
A115
D09A "A0B1
BNE
:SYN1
•BR IF NOT
A117
A002
:SYN4
LDY #2
• SET LINE LENGTH
A119
A594
LDA
COX
• INTO STMT
149
Source Code
A11B 9180
[OUTBUFF],Y
A11D 20A2A9
A120 A900
A122 B003 "A127
:SYN5 JSR GE
LDA #0
BCS :SYN6
;GO GET STMT
A124
SYN5A
A124
20DDA9
JSR
GETLL
A127
38 :
SYN6
SEC
A128
E594
SBC
COX
A12A
F020 "A14C
BEQ
:SYNIN
A12C
B013 "A141
BCS
: SYNCON
A12E
49FF
EOR
#?FF
A130
A8
TAY
A131
C8
I NY
A132
A28A
LDX
JSTMCUR
A134
207FA8
JSR
EXPLOW
A137
A597
LDA
SVESA
A139
858A
STA
STMCUR
A13B
A598
LDA
SVESA+1
A13D
858B
STA
STMCURU
A13F
D00B "A14C
BNE
:SYNIN
A141
48
SYNCON
PHA
; CONTPJ
A142
20D0A9
JSR
GNXTL
A145
68
PLA
A146
A8
TAY
A147
A28A
LDX
#STMCUR
A149
20FBA8
JSR
CONTLOW
A14C
A494
SYNIN
LDY
COX
A14E
88
SYN7
DEY
A14F
B180
LDA
[OUTBUFF],Y
A151
918A
STA
[STMCUR], Y
A153
98
TYA
A154
D0F8 "A14E
BNE
:SYN7
A156
24A6
BIT
DIRFLG
A158
502A ~A184
BVC
:SYN8
A15A
A5B1
LDA
SWVTE
A15C
ASLfl
A15C
+0A
ASL
A
A15D
ASL?
A15D
+0A
ASL
A
A15E
ASL?
A15E
+0A
ASL
A
A15F
A8
TAY
A160
A288
LDX
IENDWT
A162
20FBA8
JSR
CONTLOW
A165
38
SEC
A166
A584
LDA
VNTD
A168
E5AD
SBC
SWNTP
A16A
A8
TAY
A16B
A585
LDA
VNTD+1
A16D
E5AE
SBC
SWNTP + 1
A16F
A284
LDX
#VNTD
A171
20FDA8
JSR
CONTRACT
A174
24A6
BIT
DIRFLG
A176
1006 "A17E
BPL
:SYN9A
A178
2078B5
JSR
LDLINE
A17B
4C60A0
JMP
SYNTAX
A17E
205CB5
SYH9A
JSR
LLINE
A181
4C60A0
SYN9
JMP
SYNTAX
A184
10FB *A181
SYN8
BPL
:SYN9
A186
4C5FA9
JMP
EXECNL
A189
20A2A9
SDEL
JSR
GETSTMT
A18C
B0F3 "A181
BCS
:SYN9
A18E
20DDA9
JSR
GETLL
A191
48
PHA
;GO GET LINE LENGTH
ACU=LENGTH[ OLD-NEW]
BR NEW=OLD
BR OLD>NEW
OLD<NEW
COMPLEMENT RESULT
POINT TO STMT CURRENT
GO EXPAND
RESET STMCUR
; POINT TO STMT CURRENT
;GO CONTRACT
STMT LENGTH
MINUS ONE
GET BUFF CHAR
PUT INTO STMT TBL
TEST END
BR IF NOT
TEST FOR SYNTAX ERROR
BR IF NOT
CONTRACT WT
; CONTRACT VNT
IF STMT NOT DIRECT
THE BRANCH
ELSE LIST DIRECT LINE
THEN BACK TO SYNTAX
LIST ENTIRE LINE
; GO TO PROGRAM EXECUTOR
; GO GET LINE
; BR NOT FOUND
;GO GET LINE LENGTH
; Y
150
Source Code
A192
20D0A9
A195
68
A196
A8
A197
A28A
A199
20FBA8
A19C
4C60A0
JSR
GNXTL
PLA
TAY
LDX
SSTMCUR
;GET STMCUR DISPL
JSR
CONTLOW
,- GO DELETE
JMP
SYNTAX
;GO FOR NEXT LINE
Get a Line Number
A19F
A19F 2000D8
A1A2 9008 "A1AC
A1A4
GETLNUM-GET A LINE NO FROM ASCLT IN INBUFF
TO BINARY INTO OUTBUFF
GETLNUM
JSR CVAFP ; GO CONVERT LINE #
BCC :GLNUM ; BR IF GOOD LINE #
GLN1
A1A4 A900 LDA #0
A1A6 85F2 STA CIX
A1A8 A080 LDY #$80
A1AA 3009 "A1B5 BMI :SLNUM
SET LINE
=$8000
A1AC
2056AD
:GLNUM
A1AF
A4D5
LDY
A1B1
30F1 "A1A4
BMI
A1B3
A5D4
LDA
A1B5
:SLNUM
A1B5
84A1
STY
A1B7
85A0
STA
A1B9
20C8A2
JSR
A1BC
A5A1
LDA
A1BE
85D5
STA
A1C0
4CC8A2
JMP
SYNENT
A1C3
: SYNENT
A1C3
A001
LDY
A1C5
B195
LDA
A1C7
859E
STA
A1C9
8D8304
STA
A1CC
88
DEY
A1CD
B195
LDA
A1CF
859D
STA
A1D1
8D8204
STA
A1D4
A900
LDA
A1D6
85A9
STA
A1D8
A594
LDA
A1DA
8D8104
STA
A1DD
A5F2
LDA
A1DF
8D8004
STA
JSR CVFPI
BININT+1
:GLN1
BININT
TSLNUM+1
TSLNUM
:SETCODE
TSLNUM+1
BININT+1
:SETCODE
CONVERT FP TO IE
LOAD RESULT
BR IF LNO>32767
SET LINE #
AND LOW
OUTPUT LOW
OUTPUT HI
; AND RETURN
PERFORM LINE PRE-COMPILE
#1
[SRCADR], Y
CPC+1
SPC + 1
[SRCADR], Y
CPC
SPC
#0
STKLVL
COX
SOX
CIX
SIX
; GET PC HIGH
;SET PGM COUNTERS
SET STKLUL
SET STKLUL
MOVE
COX TO SOX
MOVE
CIX TO SIX
NEXT
A1E2
A1E5
= A1E2
20A1A2
301A "A201
GET NEXT SYNTAX CODE
AS LONG AS NOT FAILING
NEXT EQU *
JSR :NXSC
GET NEXT CODE
BR IF REL-NON-TERMINAL
A1E7
C901
CMP
#1
A1E9
902A "A215
BCC
:GETADR
A1EB
D008 ~A1F5
BNE
rTSTSUC
A1ED
2015A2
JSR
:GETADR
A1F0
90F0 ~A1E2
BCC
:NEXT
A1F2
4C6CA2
JMP
:FAIL
A1F5
C905
:TSTSUC
CMP
#5
; TEST CODE=l
; BR CODE=0 [ABS-NON-TERMINAL]
; BR CODE >1
,- CODE=l [EXTERNAL SUBROUTINE]
■ BR IF SUB REPORTS SUCCESS
; ELSE GO TO FAIL CODE
; TEST CODE = 5
151
Source Code
A1F7
9059 "A252
BCC
:POP
A1F9
20A9A2
JSR
:TERMTST
MFC
90E4 ~A1E2
BCC
:NEXT
A1FE
4C6CA2
JMP
:FAIL
A201
38
:ERNTV SEC
A202
A200
LDX
#0
A204
E9C1
SBC
#$C1
A206
B002 "A20A
BCS
:ERN1
A208
A2FF
LDX
#?FF
A20A
18
:ERN1 CLC
A20B
659D
ADC
CPC
A20D
48
PHA
A20E
8A
TXA
A20F
659E
ADC
CPC+1
A211
48
PHA
A212
4C28A2
JMP
:PUSH
= A215
:GETADR EQU
*
A215
20A1A2
JSR
:NXSC
A218
48
PHA
A219
20A1A2
JSR
:NXSC
A21C
48
PHA
A21D
9009 ~A228
BCC
:PUSH
A21F
68
PLA
A220
A8
TAY
A221
68
PLA
A222
AA
TAX
A223
98
TYA
A224
48
PHA
A225
8A
TXA
A226
48
PHA
A227
60
RTS
CODE = [2, 3, OR 4] POP UP TO
NEXT SYNTAX CODE
CODE>5 GO TEST TERMINAL
BR IF SUCCESS
ELSE GO TO FAIL CODE
RELATIVE NON TERMINAL
TOKEN MINUS
BR IF RESULT PLUS
ADD A MINUS
RESULT PLUS CPC
IS NEW CPC-1
SAVE NEW PC HIGH
GO PUSH
GET DOUBLE BYTE ADR [-1]
GET NEXT CODE
SAVE ON STACK
GET NEXT CODE
SAVE ON STACK
BR IF CODE =0
EXCHANGE TOP
2 ENTRIES ON
CPU STACK
ELSE GOTO EXTERNAL SRT VIA RTS
PUSH
PUSH TO NEXT STACK LEVEL
= A228
:PUSH EQU
*
A228
A6A9
LDX
STKLVL
A22A
E8
I NX
A22B
E8
I NX
A22C
E8
I NX
A22D
E8
I NX
A22E
F01F "A24F
BEQ
:SSTB
A230
86A9
STX
STKLVL
A232
A5F2
LDA
CIX
A234
9D8004
STA
SIX.X
A237
A594
LDA
COX
A239
9D8104
STA
SOX,X
A23C
A59D
LDA
CPC
A23E
9D8204
STA
SPC.X
A241
A59E
LDA
CPC+1
A243
9D8304
STA
SPC+l.X
A246
68
PLA
A247
859E
STA
CPC + 1
A249
68
PLA
A24A
859D
STA
CPC
A24C
4CE2A1
JMP
:NEXT
A24F
4C24B9
:SSTB JMP
ERLTL
GET STACK LEVEL
PLUS 4
;BR STACK TOO BIG
; SAVE NEW STACK LEVEL
CIX TO
STACK IX
COX TO
STACK OX
CPC TO
STACK CPC
MOVE STACKED
PC TO CPC
GO FOR NEXT
POP
= A252
: POP EQU *
A252
A6A9
LDX STKLVL
A254
D001 *A257
BNE :POPl
LOAD CPC FROM STACK PC
AND DECREMENT TO PREV STACK LEVEL
GET STACK LEVEL
BR NOT TOP OF STACK
152
Source Code
A256 60
TO SYNTAX CALLER
A257 BD8204
A25A 859D
A25C BD8304
A25F 859E
A261 CA
A262 CA
A263 CA
A264 CA
A265 86A9
A267 B003 "A26C
A269 4CE2A1
P0P1
LDA
SPC.X
STA
CPC
LDA
SPC+l.X
STA
CPC+1
DEX
DEX
DEX
DEX
STX
STKLVL
BCS
:FAIL
JMP
:NEXT
MOVE STACK PC
TO CURRENT PC
BR IF CALLER FAILING
ELSE GO TO NEXT
FAIL
= A26C
:FAIL EQU
*
A26C
20AIA2
JSR
:NXSC
A26F
30FB ~A26C
BMI
:FAIL
A271
C902
CMP
#2
A273
B008 "A27D
BCS
:TSTOR
A275
209AA2
JSR
: INCCPC
A278
209AA2
JSR
: INCCPC
A27B
D0EF "A26C
BNE
:FAIL
A27D
C903
:TSTOR CMP
#3
A27F
F0D1 "A252
BEQ
:POP
A281
B0E9 "A26C
BCS
:FAIL
A283
A5F2
LDA
CIX
A285
C59F
CMP
MAXCIX
A287
9002 "A28B
BCC
:SCIX
A289
859F
STA
MAXCIX
A28B
:SCIX
A28B
A6A9
LDX
STKLVL
A28D
BD8004
LDA
SIX.X
A290
85F2
STA
CIX
A292
BD8104
LDA
SOX,X
A295
8594
STA
COX
A297
4CE2A1
JMP
:NEXT
TERMINAL FAILED
LOOK FOR ALTERNATIVE [OR] OR
A RETURN INDICATOR
GET NEXT CODE
BR IF RNTV
TEST CODE =2
BR IF POSSIBLE OR
CODE = OR 1
INC PC BY TWO
AND CONTINUE FAIL PROCESS
TEST CODE=3
BR CODE =3 [RETURN]
CODE>3 [RNTV] CONTINUE
IF THIS CIX
IS A NEW MAX
THEN SET NEW MAX
CODE=2 [OR]
MOVE STACK INDEXES
TO CURRENT INDEXES
TRY FOR SUCCESS HERE
Increment CPC
INCCPC - INC CPC BY ONE
= A29A
: INCCPC
EQU *
A29A
E69D
INC
CPC
A29C
D002 "A2A0
BNE
: ICPCR
A29E
E69E
INC
CPC + 1
A2A0
60
: ICPCR
RTS
NXSC
GET NEXT SYNTAX CODE
A2A1
:NXSC
A2A1
209AA2
JSR
: INCCPC
; INC PC
A2A4
A200
LDX
#0
A2A6
A19D
LDA
[CPC.X]
; GET NEXT CODE
A2A8
60
RTS
; RETURN
153
Source Code
TEST A
TERMINAL CODE
A2A9
:TERMTST
A2A9
C90F
CMP
#S0F
; TEST CODE=F
A2AB
F00D
"A2BA
BEQ
:ECHNG
; BR CODE < F
A2AD
B037
"A2E6
BCS
: SRCONT
; BR CODE > F
A2AF
68
PLA
; POP RTN ADR
A2B0
68
PLA
A2B1
A90C
LDA
#:EXP-1&255
; PUSH EXP ADR
A2B3
48
PHA
; FOR SPECIAL
A2B4
A9A6
LDA
*:EXP/256
; EXP ANTV CALL
A2B6
48
PHA
A2B7
4C28A2
JMP
: PUSH
; GO PUSH
ECHNG
A2BA
A2BA
209AA2
A2BD
A000
A2BF
B19D
A2C1
A494
A2C3
88
A2C4
9180
A2C6
18
A2C7
SETCC
60
)DE
A2C8
A2C8
A494
A2CA
9180
A2CC
E694
A2CE
F001 "
A2D0
60
A2D1
4C24B9
EXTERNAL CODE TO CHANGE COX -1
| INC PC TO CODE
; GET CODE
; GET COX
; MINUS 1
| SET NEW CODE
; SET SUCCESS
; RETURN
SET CODE IN ACV AT COX AND INC COX
GET COX
SET CHAR
INC COX
BR IF NOT ZERO
DONE
GO TO LINE TOO LONG ERR
HNG
JSR
: INCCPC
LDY
#0
LDA
[CPC],Y
LDY
COX
DEY
STA
[OUTBUFF],Y
CLC
RTS
SETCODE
LDY
COX
STA
[OUTBUFF],Y
INC
COX
BEQ
: SCOVF
RTS
SCOVF
JMP
ERLTL
Exits for IF and REM
A2D4
A2FF
EIF LDX
#5FF
A2D6
9A
TXS
A2D7
A594
LDA
COX
A2D9
A4A7
LDY
STMLBD
A2DB
9180
STA
[OUTBUFF], Y
A2DD
4CB1A0
JMP
:XIF
A2E0
EREM
A2E0
EDATA
A2E0
A2FF
LDX
#?FF
A2E2
9A
TXS
A2E3
4CFBA0
JMP
: XDATA
SRCONT
SEARCH
A2E6
SRCONT
A2E6
20A1DB
JSR
SKPBLANK
A2E9
A5F2
LDA
CIX
A2EB
C5B3
CMP
SVONTX
A2ED
F016 "A305
BEQ
:SONTl
A2EF
85B3
STA
SVONTX
A2F1
A9A7
LDA
SOPNTAB/256
A2F3
A0E3
LDY
#OPNTABS,255
A2F5
A200
LDX
#0
A2F7
2062A4
JSR
SEARCH
; RESET STACK
; SET STMT LENGTH
I GO CONTINUE IF
; RESET STACK
;GO CONTINUE DATA
SEARCH OP NAME TABLE AND TEST RESULT
SKIP BLANKS
GET CURRENT INPUT INDEX
COMPARE WITH SAVED IX
BR IF SAVED IX SAME
SAVE NEW IX
SET UP FOR ONT
SEARCH
GO SEARCH
154
Source Code
A2FA
B028
"A324
BCS
:SONF
BR NOT FOUND
A2FC
86B2
STX
SVONTL
SAVE NEW CIX
A2FE
18
CLC
A2FF
A5AF
LDA
STENUM
ADD 510 TO
A301
6910
ADC
#510
ENTRY NUMBER TO
A303
85B0
STA
SVONTC
GET OPERATOR CODE
A305
A000
:SONTl
LDY
#0
A307
B19D
LDA
[CPC], Y
GET SYNTAX REQ CODE
A309
C5B0
CMP
SVONTC
DOES IT MATCH THE FOUND
A30B
F00E
"A31B
BEQ
:SONT2
BR IF MATCH
A30D
C944
CMP
#CNFNP
WAS REQ NFNP
A30F
D006
~A317
BNE
: SONTF
BR IF NOT
A311
A5B0
LDA
SVONTC
GET WHAT WE GOT
A313
C944
CMP
#CNFNP
IS IT NFNA
A315
B002
"A319
BCS
: SONTS
BR IF IT IS
A317
: SONTF
A317
38
SEC
REPORT FAIL
A318
60
RTS
A319
A5B0
: SONTS
LDA
SVONTC
GET REAL CODE
A31B
20C8A2
:SONT2
JSR
:SETCODE
GO SET CODE
A3 IE
A6B2
LDX
SVONTL
INC CIX BY
A320
86F2
STX
CIX
A322
18
CLC
REPORT SUCCESS
A323
60
RTS
DONE
A324
A900
:SONF_
LDA
#0
SET ZERO AS
A326
85B0
STA
SVONTC
SAVED CODE
A328
38
SEC
A329
60
RTS
DONE
TVAR
A32A
A32C
A900
F002 ~A330
TNVAR LDA #0
BEQ :TVAR
EXTERNAL SUBROUTINE FOR TNVAR & TSVAR
; SET NUMERIC TEST
A32E A980
TSVAR LDA
#580
A330
85D2
:TVAR
STA
TVTYPE
A332
20A1DB
JSR
SKPBLANK
A335
A5F2
LDA
CIX
A337
85AC
STA
TVSCIX
A339
20F3A3
JSR
rTSTALPH
A33C
B025
"A363
BCS
:TVFAIL
A33E
20E6A2
JSR
:SRCONT
A341
A5B0
LDA
SVONTC
A343
F008
"A34D
BEQ
:TV1
A345
A4B2
LDY
SVONTL
A347
B1F3
LDA
[INBUFF],Y
A349
C930
CMP
#$30
A34B
9016
~A363
BCC
:TVFAIL
A34D
E6F2
:TV1
INC
CIX
A34F
20F3A3
JSR
:TSTALPH
A352
90F9
"A34D
BCC
:TV1
A354
20AFDB
JSR
TSTNUM
A357
90F4
"A34D
BCC
:TV1
A359
B1F3
LDA
[INBUFF], Y
A35B
C924
CMP
#'$'
A35D
F006
"A365
BEQ
:TVSTR
A35F
24D2
BIT
TVTYPE
A361
1009
"A36C
BPL
:TVOK
A363
38
:TVFAIL
SEC
A364
60
RTS
A365
24D2
:TVSTR
BIT
TVTYPE
A367
10FA
~A363
BPL
:TVFAIL
SET STR TEST
SAVE TEST TYPE
SKIP LEADING BLANKS
GET INDEX
FOR SAVING
GO TEST FIRST CHAR
BR NOT ALPHA
IF THIS IS A
RESVD NAME
BR NOT RSVDNAME
IF NEXT CHAR AFTER
RESERVED NAME
NOT ALARM NUMERIC
THEN ERROR
INC TO NEXT CHAR
TEST ALPHA
BR IF ALPHA
TRY NUMBER
BR IF NUMBER
GET OFFENDING CHAR
IS IT 5
BR IF 5 [STRING]
THIS A NVAR SEARCH
BR 'IF NVAR
SET FAIL CODE
DONE
TEST SVAR SEARCH
BR IF SVAR
155
Source Code
A369 CS
A36A D00D ~A379
INY
BNE
:TVOK2
INC OVER $
BR ALWAYS
A36C
B1F3
:TVOK LDA
[INBUFF'
A36E
C928
CMP
#'('
A370
D007 *A379
BNE
:TVOK2
A372
C8
INY
A373
A940
LDA
#$40
A375
05D2
ORA
TVTYPE
A377
85D2
STA
TVTYPE
A379
A5AC
:TV0K2 LDA
TVSCIX
A37B
85F2
STA
CIX
A37D
84AC
STY
TVSCIX
A37F
A583
LDA
VNTP+1
A381
A482
LDY
VNTP
A383
A200
LDX
#0
A385
2062A4
JSR
SEARCH
A388
:TVRS
A388
B00A "A394
BCS
:TVS0
A38A
E4AC
CPX
TVSCIX
A38C
F04D "A3DB
BEQ
:TVSUC
A38E
2090A4
JSR
SRCNXT
A391
4C88A3
JMP
:TVRS
A394
:TVS0
A394
38
SEC
A395
A 5 AC
LDA
TVSCIX
A397
E5F2
SBC
CIX
A399
85F2
STA
CIX
A39B
A8
TAY
A39C
A284
LDX
#VNTD
A39E
207FA8
JSR
EXPLOW
A3A1
A5AF
LDA
STENUM
A3A3
85D3
STA
TVNUM
A3A5
A4F2
LDY
CIX
A3A7
88
DEY
A3A8
A6AC
LDX
TVSCIX
A3AA
CA
DEX
A3AB
BD8005
:TVS1 LDA
LBUFF.X
A3AE
9197
STA
[SVESA], Y
A3B0
CA
DEX
A3B1
88
DEY
A3B2
10F7 "A3AB
BPL
:TVS1
A3B4
A4F2
LDY
CIX
A3B6
88
DEY
A3B7
B197
LDA
[SVESA], Y
A3B9
0980
ORA
#$80
A3BB
9197
STA
[SVESA], Y
A3BD A008
A3BF A288
A3C1 207FA8
A3C4 E6B1
A3C6
A3C8
A3CA
A3CD
A3CE
A3D0
A3D2
A3D3
A3D6
A3D8
A3D9
LDY
LDX
JSR
INC
#8
#STMTAB
EXPLOW
SWVTE
A002
A900
99D200
C8
C008
90F8 "A3CA
88
B9D200
9197
88
10F8 "A3D3
LDY #2
LDA #0
:TVS1A STA
INY
CPY #8
BCC :T
DEY
:TVS2 LDA
STA
DEY
BPL
TVTYPE, Y
TVTYPE, Y
[SVESA], Y
; GET NEXT CHAR
IS IT PAREN
BR NOT PAREN
INC OVER PAREN
OR IN ARRAY
CODE TO TVTYPE
GET SAVED CIX
PUT BACK
SAVE NEW CIX
SEARCH VNT
FOR THIS GUY
BR NOT FOUND
FOUND RIGHT ONE
BR IF YES
GO SEARCH MORE
TEST THIS RESULT
SIGH:
VAR LENGTH IS
NEW CIX-OLD CIX
GO EXPAND VNT
BY VAR LENGTH
SET VARIABLE NUMBER
AND
GET DISPL TO EQU+1
MOVE VAR TO
TURN ON MSB
OF LAST CHAR
IN VTVT ENTRY
THEN EXPAND
WT BY 8
INC WT EXP SIZE
CLEAR VALUE
PART OF
ENTRY
AND THEN
PUT IN VAR TABLE
ENTRY
156
Source Code
A3DB 24D2
A3DD 5002 "A3E1
A3DF C6AC
:TVSUC BIT TVTYPE
BVC :TVNP
DEC TVSCIX
WAS THERE A PAREN
BR IF NOT
LET SYNTAX SEE PAREN
A3E1
A5AC
:TVNP
LDA
TVSCIX
; GET NEW CIX
A3E3
85F2
STA
CIX
; TO CIX
A3E5
A5AF
LDA
STENUM
; GET TABLE ENTRY NO
A3E7
3007 *
A3F0
BMI
:TVFULL
r BR IF > S7F
A3E9
0980
ORA
#?80
; MAKE IT > S7F
A3EB
20C8A2
JSR
:SETCODE
; SET CODE TO OUTPUT BUFFER
A3EE
18
CLC
; SET SUCCESS CODE
A3EF
60
RTS
; RETURN
A3F0
4C38B9
:TVFULL
JMP
ERRVSF
; GO TO ERROR RTN
TSTALPH
TEST CIX
FOR ALPHA
A3F3
: TSTALPH
A3F3
A4F2
LDY
CIX
A3F5
B1F3
LDA
[INBUFF], Y
A3F7
TSTALPH
A3F7
C941
CMP
i'ft
A3F9
9003 "
A3FE
BCC
:TAFAIL
A3FB
C95B
CMP
#$5B
A3FD
60
RTS
A3FE
3B
:TAFAIL
SEC
A3FF
60
RTS
TNCON
A400
A400
A403
A405
A407
A40A
A40C
A40E
A410
20A1DB
A5F2
85AC
2000D8
9005 "A411
A 5 AC
85F2
60
TNCON
JSR
LDA
STA
JSR
BCC
LDA
STA
RTS
EXTERNAL SUBROUTINE TO CHECK FOR NUMBER
SKBLANK
CIX
TVSCIX
CVAFP
:TNCI
TVSCIX
CIX
,- GO TEST AND CONV
; BR IF NUMBER
; RETURN FAIL
A411
A413
A90E
20C8A2
:TNC1 LDA #$0E
JSR :SETCODE
SET NUMERIC CONST
A416
A418
A41A
A41C
A41E
A41F
A420
A422
A424
A426
A42 7
A494
A200
B5D4
9180
C8
ES
E006
90F6
8494
18
60
LDY
COX
LDX
#0
2
LDA
FR0,X
STA
[OUTBUFF], Y
I NY
I NX
CPX
#6
BCC
:TNC2
STY
COX
CLC
RTS
; MOVE CONST TO STMT
TSCON
A428
A42 8
20A1DB
A42B
A4F2
A42D
B1F3
A42F
C922
A431
F002 "
A433
38
A434
6
TSCON
JSR
SKBLANK
LDY
CIX
LDA
[INBUFF], Y
CMP
#$22
BEQ
:TSC1
SEC
RTS
EXT SRT TO CHECK FOR STR CONST
GET INDEX
GET CHAR
IS IT DQUOTE
BR IF DQ
SET FAIL
RETURN
157
Source Code
A435
A90F
:TSC1
LDA
#$0F
; SET SCON CODE
A437
20C8A2
JSR
:SETCODE
A43A
A594
LDA
COX
; SET COX
A43C
85AB
STA
TSCOX
; SAVE FOR LENGTH
A43E
20C8A2
JSR
:SETCODE
; SET DUMMY FOR NOW
A441
E6F2
:TSC2
INC
CIX
; NEXT INPUT CHAR
A443
A4F2
LDY
CIX
A445
B1F3
LDA
[INBUFF],Y
A447
C99B
CMP
#CR
; IS IT CR
A449
F00C "A457
BEQ
:TSC4
; BR IF CR
A44B
C922
CMP
#$22
; IS IT DQ
A44D
F006 "A455
BEQ
:TSC3
; BR IF DQ
A44F
20C8A2
JSR
:SETCODE
; OUTPUT IT
A452
4C41A4
JMP
:TSC2
; NEXT
A455
E6F2
:TSC3
INC
CIX
; INC CIX OVER DQ
A457
18
:TSC4
CLC
A458
A594
LDA
COX
; LENGTH IS COX MIN
A45A
E5AB
SBC
TSCOX
; LENGTH BYTE COX
A45C
A4AB
LDY
TSCOX
A45E
9180
STA
[OUTBUFF],Y
; SET LENGTH
A460
18
CLC
; SET SUCCESS
A461
60
RTS
; DONE
Search a Table
TABLE FORMAT:
GARBAGE TO SKIP [N]
ASCII CHAR [N]
WITH LEAST SIGNIFICANT BYTE HAVING
MOST SIGNIFICANT BIT ON
LAST TABLE ENTRY MUST HAVE FIRST ASCII
CHAR =
ENTRY PARMS:
Y. = SKIP LENGTH
A,Y = TABLE ADR [HIGH LOW]
ARGUMENT = INBUFF + CIX
EXIT PARMS:
CARRY = CLEAR IF FOUND
X = FOUND ARGUMENT END CIX+1
SRCADR = TABLE ENTRY ADR
STENUM = TABLE ENTRY NUMBER
A462
SEARCH
A46 2
86AA
STX
SRCSKP
A464
A2FF
LDX
#?FF
A466
86AF
STX
STENUM
A468
8596
-. SRC1 STA
SRCADR+1
A46A
8495
STY
SRCADR
A46C
E6AF
INC
STENUM
A46E
A6F2
LDX
CIX
A470
A4AA
LDY
SRCSKP
A472
B195
LDA
[SRCADR], Y
A474
F027
"A49D
BEQ
:SRCNF
A476
A900
LDA
#0
A478
08
PHP
A479
BD8005
•SRC2 LDA
LBUFF.X
A47C
297F
AND
#?7F
A47E
C92E
CMP
# ' . '
A480
F01D
"A49F
BEQ
:SRC5
A482
:SRC2A
A482
5195
EOR
[SRCADR], Y
A484
ASLA
A484
+0A
ASL
A
A485
F002
"A489
BEQ
:SRC3
SAVE SKIP FACTOR
SET ENTRY NUMBER
TO ZERO
SET SEARCH ADR
INC ENTRY NUMBER
GET ARG DISPL
GET SKIP LENGTH
GET FIRST CHAR
BR IF EOT
SET STATUS = EQ
AND PUSH IT
GET INPUT CHAR
TURN OFF MSB
IF WILD CARD
THEN BR
EX-OR WITH TABLE CHAR
SHIFT MSB TO CARRY
BR IF [ARG=TAB] CHAR
158
Source Code
A487
68
PLA
; POP STATUS
A488
08
PHP
1 PUSH NE STATUS
A489
C8
:SRC3
INY
;INC TABLE INDEX
A48A
E8
INX
;INC ARG INDEX
A48B
90EC
*A479
BCC
:SRC2
; IF TABLE MSB OFF, CO
;ELSE END OF ENTRY
A48D
28
PLP
;GET STATUS
A48E
F00B
"A49B
BEQ
: SRCFND
rBR IF NO MIS MATCH
A490
SRCNXT
A490
18
CLC
A491
98
TYA
;ACV=ENTRY LENGTH
A492
6595
ADC
SRCADR
;PLUS START ADR [L]
A494
A8
TAY
:TO Y
A495
A596
LDA
SRCADR+1
;ETC
A497
6900
ADC
#0
A499
D0CD
"A468
BNE
:SRC1
;BR ALLWAYS
A49B
18
:SRCFND
CLC
; INDICATE FOUND
A49C
60
RTS
A49D
38
:SRCNF
SEC
; INDICATE NOT FOUND
A49E
60
RTS
A49F
A902
!sRC5
LDA
#2
; IF NOT
A4A1
C5AA
CMP
SRCSKP
; STMT NAME TABLE
A4A3
D0DD
"A482
BNE
:SRC2A
; THEN IGNORE
A4A5
B195
:SRC6
LDA
[SRCADR],Y
;TEST MSB OF TABLE
A4A7
3003
"A4AC
BMI
:SRC7
; IF ON DONE
A4A9
C8
INY
; ELSE
A4AA
D0F9
"A4A5
BNE
:SRC6
; LOOK AT NEXT CHAR
A4AC
38
:SRC7
SEC
; INDICATE MSB ON
A4AD
B0DA
~A489
BCS
:SRC3
; AND RE-ENTER CODE
Statement Name Table
A4AF
SNTAB- STATEMENT NAME TABLE
EACH ENTRY HAS SYNTAX TABLE ADR PTR
FOLLOWED BY STMT NAME
A4AF
C7A7
DW
:SREM-1
A4B1
5245CD
DC
'REM'
A4B4
CAA7
DW
:SDATA-1
A4B6
444154C1
DC
' DATA '
A4BA
F3A6
DW
:SINPUT-1
A4BC
494E5055D4
DC
'INPUT'
A4C1
BCA6
DW
:SCOLOR-l
A4C3
434F4C4FD2
DC
'COLOR'
A4C8
32A7
DW
:SLIST-1
A4CA
4C4953D4
DC
'LIST'
A4CE
23A7
DW
:SENTER-1
A4D0
454E5445D2
DC
'ENTER'
A4D5
BFA6
DW
:SLET-1
A4D7
4C45D4
DC
'LET'
A4DA
93A7
DW
:SIF-1
A4DC
49C6
DC
'IF'
A4DE
D1A6
DW
:SFOR-l
A4E0
464FD2
DC
'FOR'
A4E3
E9A6
DW
:SNEXT-1
159
Source Code
A4E5 4E4558D4
A4E9
BCA6
DW
:SG0T0-1
A4EB
474F54CF
DC
' GOTO '
A4EF
BCA6
DW
:SGOTO-l
A4F1
474F2054CF
DC
'GO TO'
A4F6
BCA6
DW
:SGOSUB-l
A4F8
474F5355C2
DC
'GOSUB'
A4FD
BCA6
DW
:STRAP-1
A4FF
545241D0
DC
'TRAP'
A503
BDA6
DW
:SBYE-1
A505
4259C5
DC
'BYE'
A508
BDA6
DW
:SCONT-l
A50A
434F4ED4
DC
' CONT '
A50E
5FA7
DW
:SCOM-l
A510
434FCD
DC
'COM'
A513
20A7
DW
:SCLOSE-l
A515
434C4F53C5
DC
'CLOSE'
A51A
BDA6
DW
:SCLR-1
A51C
434CD2
DC
'CLR'
A51F
BDA6
DW
:SDEG-1
A521
4445C7
DC
'DEC
A524
5FA7
DW
iSDXM-1
A526
4449CD
DC
'DIM'
A529
BDA6
DW
:SEND-1
A52B
454EC4
DC
'END'
A52E
BDA6
DW
:SNEW-1
A530
4E45D7
DC
'NEW'
A533
19A7
DW
:SOPEN-l
A535
4F5045CE
DC
'OPEN'
A539
23A7
DW
:SL0AD-1
A53B
4C4F4104
DC
'LOAD'
A53F
23A7
DW
:SSAVE-1
A541
534156C5
DC
'SAVE'
A545
40A7
DW
:SSTATUS-1
A547
5354415455
D3
DC
' STATUS '
A54D
49A7
DW
:SNOTE-l
A54F
4E4F54C5
DC
' NOTE '
A553
49A7
DW
:SPOINT-l
A555
504F494ED4
DC
'POINT '
A55A
17A7
DW
:SXIO-l
A55C
5849CF
DC
'XIO'
A55F
62A7
DW
:SON-l
A561
4FCE
DC
'ON'
A563
5CA7
DW
:SPOKE-l
A565
504F4BC5
DC
' POKE '
A569
FBA6
DW
:SPRINT-1
A56B
5052494ED4
DC
'PRINT '
A570
BDA6
DW
:SRAD-1
A572
5241C4
DC
'RAD'
A575
F4A6
DW
:SREAD-1
160
Source Code
A577
524541C4
A57B
EEA6
A57D
524553544F
52C5
A584
BDA6
A586
5245545552
CE
A58C
26A7
A58E
5255CE
A591
BDA6
A593
53544FD0
A597
BDA6
A599
504FD0
A59C
FBA6
A59E
BF
A59F
E7A6
A5A1
4745D4
A5A4
B9A6
A5A6
5055D4
A5A9
BCA6
A5AB
4752415048
4943D3
A5B3
5CA7
A5B5
504C4FD4
A5B9
5CA7
A5BB
504F534954
494FCE
A5C3
BDA6
A5C5
444FD3
A5C8
5CA7
A5CA
4452415754
CF
A5D0
5AA7
A5D2
534554434F
4C4FD2
A5DA
E1A6
A5DC
4C4F434154
C5
A5E2
58A7
A5E4
534F554EC4
A5E9
FFA6
A5EB
4C5052494E
D4
A5F1
BDA6
A5F3
43534156C5
A5F8
BDA6
A5FA
434C4F41C4
A5FF
BFA6
A601
00
A602
8000
A604
2A4552524F
522D20
A60C
A0
DW
DC
DW
DC
DW
DC
DW
DC
DW
DC
DW
DC
DW
DC
DW
DC
DW
DC
DW
DC
DW
DC
DW
DC
DW
DC
DW
DC
DW
DC
DW
DC
DW
DC
DW
DC
DW
DC
DW
DB
DB
DB
:SREST-1
'RESTORE'
:SRET-1
'RETURN'
:SRUN-1
'RUN'
:SSTOP-l
' STOP '
:SPOP-l
'POP'
:SPRINT-1
'?'
:SGET-1
'GET'
:SPUT-1
'PUT '
:SGR-1
'GRAPHICS'
:SPLOT-l
1 PLOT '
:SPOS-l
'POSITION'
:SDOS-l
'DOS '
:SDRAWTO-l
' DRAWTO '
:SSETCOLOR-l
'SETCOLOR'
:SLOCATE-l
'LOCATE'
:SSOUND-l
'SOUND'
:SLPRINT-1
'LPRINT'
:SCSAVE-1
'CSAVE '
:SCLOAD-l
'CLOAD'
:SILET-1
580,00
' * ERROR- '
$A0
161
Source Code
Syntax Tables
Syntax Table OP Codes
=
0000
=
0001
=
0002
=
0003
=
0004
=
000E
=
000F
<EXP> =(<
A60D
A60D
+2B
A60E
A60E
+BF
A60F
A60F
+2C
A610
A610
+DE
A611
A611
+0 2
A612
A612
+C6
A613
A613
+BA
A614
AG14
+0 2
A615
A615
+CD
A616
A616
+D8
A617
A617
+03
<UNARY>
A618
A618
+25
A619
A619
+0F
A61A
+35
A61B
A61B
+02
A61C
A61C
+26
A61D
A61D
+0F
A61E
+36
A61F
A61F
+02
A620
A620
+28
A621
A621
+03
<IMV
> = <
A622
A622
+FD
A623
+02
A624
A624
+E8
A625
+02
A626
A626
+01
ANTV
EQU
$00
ESRT
EQU
$01
OR
EQU
$02
RTN
EQU
$03
NULL
EQU
$04
VEXP
EQU
$0E
CHNG
EQU
$0F
ABSOLUTE NON TERMINAL VECTOR
FOLLOWED BY 2 BYTE ADR -1
EXTERNAL SUBROUTINE CALL
FOLLOWED BY 2 BYTE ADR -1
ALTERNATIVE, BNF OR (])
RETURN, (#)
ACCEPT TO THIS POINT ( s, )
SPECIAL NTV FOR EXP (<EXP>)
CHANGE LAST OUTPUT TOKEN
(<EXP>)<NOP> | <UNARYxEXP> | <NV><NOP>#
SYN
CLPRN
DB
CLPRN
SYN
JS, :EXP
DB
$80+( ( (:EXP-*
&$7F) XOR $40 )
SYN
CRPRN
DB
CRPRN
SYN
JS, :NOP
DB
$80+( ( ( :NOP-*
6,$7F) XOR $40 )
SYN
:OR
DB
:0R
SYN
JS, : UNARY
DB
$80+ ( ( ( : UNARY
-*)S,$7F) XOR $40 )
SYN
JS, :EXP
DB
$80+( ( ( :EXP-*
&$7F) XOR $40 )
SYN
:OR
DB
:OR
SYN
JS, :NV
DB
$80+( ( ( :NV-*)
«$7F) XOR $40 )
SYN
JS, :NOP
DB
$80+( ( ( :NOP-*
&$7F) XOR $40 )
SYN
:RTN
DB
:RTN
+ I - I NOT#
UNARY SYN
CPLUS
DB
CPLUS
SYN
:CHNG,CUPLUS
DB
:CHNG
DB
CUPLUS
SYN
:OR
DB
:OR
SYN
CMINUS
DB
CMINUS
SYN
:CHNG,CUMINUS
DB
:CHNG
DB
CUMINUS
SYN
:OR
DB
:OR
SYN
CNOT
DB
CNOT
SYN
:RTN
DB
:RTN
<NVAR> <NCON> | <STCOMP>#
:NV SYN JS, :NFUN, : OR
DB $80+( ( ( :NFUN-*)&$7F) XOR $40 )
DB :OR
SYN JS, :NVAR, : OR
DB $80+( ( ( :NVAR-*)&$7F) XOR $40 )
DB :OR
SYN :ESRT, AD, :TNCON-l, : OR
DB :ESRT
162
Source Code
A627 +FFA3
A629 +02
A62A
A62A +00
A62B +7DA6
A62D
A62D +03
<NOP> = <
A62E
A62E +C4
A62F
A62F +9E
A630
A630 +02
A631
A631 +03
<OP> = ** | * ] /| <
A632
A632
+23
A633
+02
A634
A634
+25
A635
+02
A636
A636
+26
A637
+02
A638
A638
+24
A639
+02
A63A
A63A
+ 27
A63B
+02
A63C
A63C
+1D
A63D
+0 2
A63E
A63E
+1F
A63F
+02
A640
A640
+ 1E
A641
+02
A642
A642
+20
A643
+02
A644
A644
+21
A645
+02
A646
A646
+22
A647
+02
A648
A648
+ 2A
A649
+0 2
A64A
A64A
+ 29
A64B
A64B
+03
<NVAR> =
A64C
A64C
+01
A64D
+ 29A3
A64F
A64F
+C2
A650
A650
+0 3
DW
( :TNCON-l )
DB
:OR
SYN
:ANTV,AD, :STCOMP-l
DB
:ANTV
DW
( :STCOMP-l)
SYN
:RTN
DB
:RTN
EXP> | &#
NOP SYN
JS, :OP
DB
580+( ( ( :OP-*)&$7F) XOR $40 )
SYN
JS, :EXP
DB
$80+( ( ( :EXP-*)&$7F) XOR $40 )
SYN
:OR
DB
:OR
SYN
:RTN
DB
:RTN
:= | S= | <> | < | > |= | AND | OR#
OP SYN
CEXP, :OR
DB
CEXP
DB
:OR
SYN
CPLUS, :OR
DB
CPLUS
DB
:OR
SYN
CMINUS, :OR
DB
CMINUS
DB
:OR
SYN
CMUL, :OR
DB
CMUL
DB
:0R
SYN
CDIV, :OR
DB
CDIV
DB
:OR
SYN
CLE, :OR
DB
CLE
DB
:OR
SYN
CGE, :OR
DB
CGE
DB
:OR
SYN
CNE, :0R
DB
CNE
DB
:OR
SYN
CLT, :OR
DB
CLT
DB
:OR
SYN
CGT, :OR
DB
CGT
DB
:OR
SYN
CEQ, :OR
DB
CEQ
DB
:OR
SYN
CAND, :OR
DB
CAND
DB
:OR
SYN
COR
DB
COR
SYN
:RTN
DB
:RTN
<TNVAR> <NMAT>#
:ESRT, AD, :TNVAR-1
DB
:ESRT
DW
( :TNVAR-1 )
SYN
JS, :NMAT
DB
SYN
$80+ ( ( ( :NMAT-*'
:RTN
)&$7F) XOR
DB
:RTN
S40 )
163
Source Code
<NMAT> = ( <EXP> <NMAT2> ) | &#
A651
: NMAT SYN
CLPRN, :CHNG,CALPRN
A651
+2B
DB
CLPRN
A652
+0F
DB
:CHNG
A653
+3 8
DB
CALPRN
A654
SYN
:VEXP
A654
+0E
DB
:VEXP
A655
SYN
JS, :NMAT2
A655
+C4
DB
$80+((( :NMAT2-*)&$7F) XOR $40 )
A656
SYN
CRPRN
A656
+2C
DB
CRPRN
A657
SYN
:0R
A657
+02
DB
:0R
A658
SYN
:RTN
A658
+0 3
DB
:RTN
<NMAT2>
= ,<EXP> | &#
A659
: NMAT 2 SYN
CCOM, :CHNG,CACOM
A659
+12
DB
CCOM
A65A
+0F
DB
:CHNG
A65B
+3C
DB
CACOM
A65C
SYN
:VEXP
A65C
+0E
DB
:VEXP
A65D
SYN
:OR
A65D
+02
DB
:OR
A65E
SYN
:RTN
A65E
+03
DB
:RTN
<NFUN> =
<NFNP><NFP> | <NFSP><SFP> | <NFUSR>#
A65F
:NFUN SYN
CNFNP
A65P
+44
DB
CNFNP
A660
SYN
JS, :NFP
A660
+D2
DB
$80+( ( ( :NFP-*)&$7F) XOR $40 )
A661
SYN
:OR
A661
+02
DB
:OR
A662
SYN
:ANTV, AD, :NFSP-1
A662
+00
DB
:ANTV
A663
+CDA7
DW
( :NFSP-1)
A665
SYN
JS, :SFP
A665
+D3
DB
$80+( ( ( :SFP-*)S,$7F) XOR $40 )
A666
SYN
:OR
A666
+02
DB
:OR
A667
SYN
JS, :NFUSR
A667
+C2
DB
$80+( (( :NFUSR-*)&$7F) XOR $40 )
A668
SYN
:RTN
A668
+03
DB
:RTN
<NFUSR> =
= USR(
<PUSR> )#
A669
:NFUSR SYN
CUSR
A669
+3F
DB
CUSR
A66A
SYN
CLPRN, :CHNG, CFLPRN
A66A
+2B
DB
CLPRN
A66B
+0F
DB
:CHNG
A66C
+3A
DB
CFLPRN
A66D
SYN
:ANTV, AD, :PUSR-1
A66D
+00
DB
:ANTV
A66E
+D9A7
DW
( :PUSR-1)
A670
SYN
CRPRN
A670
+2C
DB
CRPRN
A671
SYN
:RTN
A671
+03
DB
:RTN
<NFP> = ( <EXP> )#
A672
:NFP SYN
CLPRN, :CHNG, CFLPRN
A672
+2B
DB
CLPRN
A673
+0F
DB
:CHNG
A674
+3A
DB
CFLPRN
A675
SYN
:VEXP
164
Source Code
A67 5 +0E DB
A676 SYN
A676 +2C DB
A677 SYN
A677 +03 DB
<SFP> = <STR> )#
A678 tS
A678 +2B
A679 +0F DB
A67A +3A DB
A67B SYN
A67B +C7 DB
A67C SYN
A67C +2C DB
A67D SYN
A67D +03 DB
:VEXP
CRPRN
CRPRN
:RTN
:RTN
SYN CLPRN, :CHNG,CFLPRN
DB CLPRN
:CHNG
CFLPRN
JS, :STR
S80+( ( ( :STR-*)&$7F) XOR $40
CRPRN
CRPRN
:RTN
:RTN
<STCOMP> = <STR> <SOP> <STR>#
A67E
A67E +C4
A67F
A67F +E3
A680
A680 +C2
A681
A681 +03
:STCOMP SYN JS, :STR
DB $80+( ( ( :STR-*)&?7F) XOR $40 )
SYN JS, :SOP
DB $80+( ( ( :SOP-*)S,$7F) XOR $40 )
SYN JS, :STR
DB $80+( ( ( :STR-*)&$7F) XOR $40 )
SYN : RTN
DB : RTN
<STR> = <SFUN> | <SVAR> | <SCON>#
A682
:STR SYN
JS, :SFUN
A682 +C8
DB
$80+ ( ( ( :SFUN-*)&$7F) XOR $40 )
A683
SYN
:OR
A683 +02
DB
:OR
A684
SYN
JS , : SVAR
A684 +CB
DB
$80+( ( ( :SVAR-*)&$7F) XOR $40 )
A685
SYN
:OR
A685 +02
DB
:OR
A686
SYN
:ESRT,AD, :TSCON-l
A686 +01
DB
:ESRT
A687 +27A4
DW
( :TSCON-l)
A689
SYN
:RTN
A689 +03
DB
:RTN
<SFUN> =
SFNP<NFP>#
A68A
:3FUN SYN
:ANTV, AD, :SFNP-1
A68A +00
DB
:ANTV
A68B +D5A7
DW
( :SFNP-1)
A68D
SYN
JS, :NFP
A68D +A5
DB
$80+( ( ( :NFP-*)&$7F) XOR $40 )
A68E
SYN
:RTN
A68E +03
DB
:RTN
< SVAR > =
< TSVAR
><SMAT>#
A68F
:SVAR SYN
:ESRT,AD, :TSVAR-1
A68F +01
DB
:ESRT
A690 +2DA3
DW
( :TSVAR-1)
A692
SYN
JS , : SMAT
A692 +C2
DB
$80+( ( ( :SMAT-*)&$7F) XOR $40 )
A693
SYN
:RTN
A693 +03
DB
:RTN
<SMAT> = ( <EXP> <SMAT2>
&#
A694
A694 +2B
A695 +0F
A696 +37
:SMAT SYN CLPRN. : CHNG, CSLPRN
DB CLPRN
DB :CHNG
DB CSLPRN
165
Source Code
A697
SYN
:VEXP
A697
+0E
DB
:VEXP
A698
SYN
JS, :SMAT2
A698
+C4
DB
$80+ ( ( ( :SMAT2-*
)&$7F) XOR $40 )
A699
SYN
CRPRN
A699
+ 2C
DB
CRPRN
A69A
SYN
:0R
A69A
+02
DB
:0R
A69B
SYN
:RTN
A69B
+03
DB
:RTN
<SMAT2>
= , <EXP> | &#
A69C
:SMAT2 SYN
CCOM, :CHNG
, CACOM
A69C
+ 12
DB
CCOM
A69D
+0F
DB
:CHNG
A69E
+3C
DB
CACOM
A69F
SYN
:VEXP
A69F
+0E
DB
:VEXP
A6A0
SYN
:OR
A6A0
+02
DB
:0R
A6A1
SYN
:RTN
A6A1
+03
DB
:RTN
<SOP> =
< ><#
A6A2
:SOP
A6A2
SYN
CLE, :CHNG,CSLE,
:OR
A6A2
+1D
DB
CLE
A6A3
+0F
DB
:CHNG
A6A4
+2F
DB
CSLE
A6A5
+02
DB
:0R
A6A6
SYN
CNE, :CHNG,CSNE,
:OR
A6A6
+1E
DB
CNE
A6A7
+0F
DB
:CHNG
A6A8
+30
DB
CSNE
A6A9
+02
DB
:OR
A6AA
SYN
CGE, :CHNG,CSGE,
:OR
A6AA
+1F
DB
CGE
A6AB
+0F
DB
:CHNG
A6AC
+31
DB
CSGE
A6AD
+02
DB
:OR
A6AE
SYN
CLT, :CHNG,CSLT,
:OR
A6AE
+ 20
DB
CLT
A6AF
+0F
DB
:CHNG
A6B0
+3 2
DB
CSLT
A6B1
+02
DB
:OR
A6B2
SYN
CGT, :CHNG,CSGT,
:OR
A6B2
+21
DB
CGT
A6B3
+0F
DB
:CHNG
A6B4
+3 3
DB
CSGT
A6B5
+02
DB
:OR
A6B6
SYN
CEQ, :CHNG,CSEQ
A6B6
+22
DB
CEO
A6B7
+ 0F
DB
:CHNG
A6B8
+34
DB
CSEO
A6B9
SYN
:RTN
A6B9
+03
DB
:RTN
<PUT> =
<D1>,<EXP><EOS>#
A6BA
:SPUT
A6BA
SYN
CPND, :VEXP
A6BA
+1C
DB
CPND
A6BB
+0E
DB
:VEXP
A6BC
SYN
CCOM
A6BC
+12
DB
CCOM
166
Source Code
< > = <EXP><EOS>#
A6BD
STRAP
A6BD
SGOTO
A6BD
SGOSUB
A6BD
SGR
A6BD
SCOLOR
A6BD
XEOS SYN
:VEXP
A6BD
+0E
DB
:VEXP
< >
= <EOS>#
A6BE
SCSAVE
A6BE
SCLOAD
A6BE
SDOS
A6BE
SCLR
A6BE
SRET
A6BE
SEND
A6BE
SSTOP
A6BE
SPOP
A6BE
SNEW
A6BE
SBYE
A6BE
SCONT
A6BE
SDEG
A6BE
SRAD
A6BE
SYN
JS, :EOS
A6BE
+FA
DB
$80+( ( ( sEO
A6BF
SYN
:RTN
A6BF
+03
DB
:RTN
<LET> = <NVAR> =<EXP><EOS> <SVAR> = <STR>< EOS>#
A6C0
:SLET
A6C0
:SILET
A6C0
SYN
:ANTV, AD, :NVAR-1
A6C0
+00
DB
:ANTV
A6C1
+4BA6
DW
( :NVAR-1)
A6C3
SYN
CEQ, :CHNG,CAASN
A6C3
+22
DB
CEQ
A6C4
+0F
DP,
:CHNG
A6C5
+2D
DB
CAASN
A6C6
SYN
:VEXP
A6C6
+0E
DB
:VEXP
A6C7
SYN
JS, :EOS
A6C7
+F1
DB
580+( ( ( :EOS-*)&$7F) XOR 540 )
A6C8
SYN
:OR
A6C8
+02
DB
:OR
A6C9
SYN
JS, :SVAR
A6C9
+86
DB
?80+( ( ( :SVAR-*)&$7F) XOR $40 )
A6CA
SYN
CEQ, :CHNG,CSASN
A6CA
+22
DB
CEQ
A6CB
+0F
DB
:CHNG
A6CC
+2E
DB
CSASN
A6CD
SYN
: ANTV, AD, : STR-1
A6CD
+00
DB
:ANTV
A6CE
+81A6
DW
( :STR-1 )
A6D0
SYN
JS, :EOS
A6D0
+E8
DB
$80+ ( ( ( :EOS-*)&$7F) XOR $40 )
A6D1
SYN
:RTN
A6D1
+03
DB
:RTN
<FOR> = <
TNVAR> = <EXP>
TO <EXPxFSTEPxEOS>#
A6D2
:SFOR SYN : ESRT, AD, :TNVAR-1
A6D2
+01
DB
:ESRT
A6D3
+2 9A3
DW
( :TNVAR-1 )
A6D5
SYN
CEQ, :CHNG, CAASN
A6D5
+22
DB
CEQ
A6D6
+0F
DB
:CHNG
A6D7
+2D
DB
CAASN
167
Source Code
A6D8
SYN
:VEXP
A6D8
+0E
DB
:VEXP
A6D9
SYN
CTO
A6D9
+19
DB
CTO
A6DA
SYN
:VEXP
A6DA
+0E
DB
:VEXP
A6DB
SYN
JS, :FSTEP
A6DB
+C3
DB
$80+( ( ( :FSTEP-*)6,$7F) XOR 540 )
A6DC
SYN
JS, :EOS
A6DC
+DC
DB
$80+( ( ( :E0S-*)&$7F) XOR $40 )
A6DD
SYN
:RTN
A6DD
+03
DB
:RTN
<FSTEP>
= STEP<EXP> | &
A6DE
:FSTEP
A6DE
SYN
CSTEP
A6DE
+1A
DB
CSTEP
A6DP
SYN
:VEXP
A6DF
+0E
DB
:VEXP
A6E0
SYN
:0R
A6E0
+02
DB
:OR
A6E1
SYN
:RTN
A6E1
+03
DB
:RTN
< LOCATE
> = <EXP>,<EXP>,
,<TNVAR><EOL>#
A6E2
: SLOCATE
A6E2
SYN
:VEXP
A6E2
+0E
DB
:VEXP
A6E3
SYN
CCOM
A6E3
+12
DB
CCOM
A6E4
SYN
:VEXP
A6E4
+0E
DB
:VEXP
A6E5
SYN
CCOM
A6E5
+12
DB
CCOM
A6E6
SYN
JS, :SNEXT
A6E6
+C4
DB
$80+( ( t :SNEXT-*)&?7F) XOR $40 )
A6E7
SYN
:RTN
A6E7
+03
DB
:RTN
<GET> =
<D1>,
<TNVAR>#
A6E8
:SGET
A6E8
SYN
JS, :D1
A6E8
+DD
DB
$80+( ( ( :D1-*)S$7F) XOR $40 )
A6E9
SYN
CCOM
A6E9
+12
DB
CCOM
<NEXT> = <TNVAR><EOS>#
A6EA
:SNEXT SYN
:ESRT, AD,
:TNVAR-1
A6EA
+01
DB
:ESRT
A6EB
+2 9A3
DW
( :TNVAR-1)
A6ED
SYN
JS , : EOS
A6ED
+CB
DB
$80+( ( ( :EOS-*:
&$7F) XOR
$40 )
A6EE
SYN
:RTN
A6EE
+03
DB
:RTN
< RESTORE > =
= <EXP><EOS> |
<EOS>#
A6EF
:SREST SYN
:VEXP
A6EF
+0E
DB
: VEXP
A6F0
SYN
JS, :EOS
A6F0
+C8
DB
$80+( ( ( :EOS-*
|&$7F) XOR
$40 )
A6F1
SYN
:OR
A6F1
+02
DB
:OR
A6F2
SYN
JS , : EOS
A6F2
+C6
DB
$80+( ( ( :EOS-*
)&$7F) XOR
$40 )
A6F3
SYN
:RTN
A6F3
+03
DB
:RTN
168
Source Code
<INPUT> = <OPD><READ>#
A6F4 :SINPUT SYN
A6F4 +P8 DB
<READ> = <NSVARL> <EOS>#
JS, :OPD
$80+( ( ( :0PD-*)&$7F) XOR $40 )
A6F5
A6F5 +DB
A6F6
A6F6 +C2
A6F7
A6F7 +03
EOS = : | CR#
A6F8
A6F8 +14
A6F9
A6F9 +02
A6FA
A6FA +16
A6FB
A6FB +03
A6FC
A6FC
A6FC +C9
A6FD
A6FD +BB
A6FE
A6FE +02
A6FF
A6FF +ED
A700
A700
A700 +00
A701 +9FA7
A703
A703 +B5
A704
A704 +03
:SREAD SYN JS , :NSVRL
DB 580+ ( ( ( :NSVRL-*)&$7F) XOR $40 )
SYN JS, :EOS
DB $80+( ( ( :EOS-*)&$7F) XOR $40 )
SYN : RTN
DB :RTN
:EOS SYN
CEOS
DB
CEOS
SYN
:OR
DB
:OR
SYN
CCR
DB
CCR
SYN
:RTN
DB
:RTN
;EOS> |
<D1xPR1><EOS>
:SPRINT
SYN
JS, :D1
DB
$80+( ( ( :D1-*)&$7F) XOR $40 )
SYN
JS, :EOS
DB
$80+( ( ( :EOS-*)s,$7F) XOR $40
)
SYN
:OR
DB
:OR
SYN
JS, :OPD
DB
$80+( ( ( :OPD-*)&$7F) XOR $40
)
:SLPRINT
SYN
:ANTV,AD, :PR1-1
DB
:ANTV
DW
( :PR1-1)
SYN
JS, :EOS
DB
$80+((( :EOS-*)£,$7F) XOR $40
)
SYN
:RTN
DB
:RTN
<D1> = <CPNDxEXP>#
: Dl
A705
A705 +1C
A706
A706 +0E
A707
A707 +0 3
SYN CPND
DB CPND
SYN :VEXP
DB :VEXP
SYN :RTN
DB : RTN
<NSVAR> = <NVAR> | <SVAR>#
A708
A708 +01
A709 +29A3
A70B
A70B +02
A70C
A70C +01
A70D +2DA3
A70F
A70F +03
:NSVAR SYN
DB
DW
SYN
DB
SYN
DB
DW
SYN
DB
:ESRT,AD, :TNVAR-1
:ESRT
( :TNVAR-1 )
:OR
:OR
:ESRT, AD, :TSVAR-1
:ESRT
( :TSVAR-1)
:RTN
:RTN
<NSVRL> = <NSVAR><NSV2> | &#
A710
A710 +B8
A711
:NSVRL SYN JS , : NSVAR
DB $80+( ( ( :NSVAR-*)&$7F) XOR $40 )
SYN JS, :NSV2
169
Source Code
A711 +C3
DB
$80+( ( ( :NSV2-*)S,$7F) XOR $40 )
A712
SYN
:OR, :RTN
A712 +02
DB
:0R
A713 +03
DB
:RTN
<NSV2>
= ,<NSVRL> | &#
A714
:NSV2 SYN CCOM
A714 +12
DB
CCOM
A715
SYN
JS, :NSVRL
A715 +BB
DB
$80+( ( ( :NSVRL-*)&$7F) XOR $40 )
A716
SYN
:OR, :RTN
A716 +02
DB
:OR
A717 +03
DB
:RTN
<XIO> =
<AEXP>
, <D2S> <
FS>,<AEXP><EOS>#
A718
:SX10
A718
SYN
:VEXP
A718 +0E
DB
:VEXP
A719
SYN
CCOM
A719 +12
DB
CCOM
<OPEN>
= <D1>,
<EXP>,<
EXP>,<FS>,<EOS>#
A71A
:SOPEN
A71A
SYN
JS, :D1
A71A +AB
DB
$80+( ( ( :D1-*)S$7F) XOR $40 )
A71B
SYN
CCOM
A71B +12
DB
CCOM
A71C
SYN
JS, :TEXP
A71C +F9
DB
$80+( ( ( :TEXP-*)S,$7F) XOR $40 )
A71D
SYN
CCOM
A71D +12
DB
CCOM
A71E
SYN
JS, :FS
A71E +F3
DB
$80+(((:FS-*)&$7F) XOR $40 )
A71F
SYN
JS, :EOS
A71F +99
DB
$80+( ( ( :EOS-*)&$7F) XOR $40 )
A720
SYN
:RTN
A720 +03
DB
:RTN
< CLOSE >
= <D1xEOS>#
A721
:SCLOSE
A721
SYN
JS, :D1
A721 +A4
DB
$80+( ( ( :D1-*)&$7F) XOR $40 )
A722
SYN
JS, :EOS
A722 +96
DB
$80+( ( ( :EOS-*)&$7F) XOR $40 )
A723
SYN
:RTN
A723 +03
DB
:RTN
< > = <FS><EOS>#
A724
: SENTER
A724
:SLOAD
A724
:SSAVE
A724
SYN
JS, :FS
A724 +ED
DB
$80+( ( ( :FS-*)i$7F) XOR $40 )
A725
SYN
JS, :EOS
A725 +93
DB
$80+( ( ( :EOS-*)&$7F) XOR $40 )
A726
SYN
:RTN
A726 +03
DB
:RTN
<RUN> =
<FS><EOS2> <EOS2>#
A727
:SRUN
A727
SYN
JS, :FS
A727 +EA
DB
$80+( ( ( :FS-*)&$7F) XOR $40 )
A728
SYN
JS, :EOS
A728 +90
DB
$80+( ( ( :EOS-*)£,$7F) XOR $40 )
A729
SYN
■ OR
A729 +02
DB
:OR
170
Source Code
A72A
SYN
JS, :E0S
A72A
+8E
DB
$80+( ( (:E0S-*)&$7F) XOR $40 )
A72B
SYN
:RTN
A72B
+03
DB
:RTN
<OPD> = <
D1
>, | #
A72C
:0PD
A72C
SYN
JS, :D1
A72C
+99
DB
$80+(( (:D1-*)&S7F) XOR $40 )
A72D
:0PDX SYN
CCOM
A72D
+ 12
DB
CCOM
A72E
SYN
:0R
A72E
+02
DB
:0R
A72F
SYN
JS, :D1
A72F
+96
DB
$80+( (( :D1-*)6,$7F) XOR $40 )
A730
SYN
CSC
A730
+ 15
DB
CSC
A731
SYN
:0R
A731
+02
DB
:0R
A732
SYN
:RTN
A732
+03
DB
:RTN
<UST> = <
FS>;<L2> ! <L2>#
i
A733
:SL1ST
A733
SYN
JS, :FS
A733
+DE
DB
$80+( ( ( :FS-*)6,$7F) XOR $40 )
A734
SYN
JS, :EOS
A734
+84
DB
$80+( ( ( :E0S-*)&$7F) XOR $40 )
A735
SYN
:0R
A735
+02
DB
:0R
A736
SYN
JS , : FS
A736
+DB
DB
$80+( ( ( :FS-*)E,$7F) XOR $40 )
A737
SYN
CCOM
A737
+ 12
DB
CCOM
A738
SYN
JS, :LIS
A738
+C4
DB
$80+( ( t :LIS-*)&$7F) XOR $40 )
A739
SYN
:0R
A739
+02
DB
:0R
A73A
SYN
JS, :LIS
A73A
+C2
DB
$80+( ( ( :LIS-*)&$7F) XOR $40 )
A73B
SYN
:RTN
A73B
+03
DB
:RTN
<LIS> = <L1>
<EOS2>#
A73C
:LIS
A73C
SYN
:ANTV,AD, :L1-1
A73C
+00
DB
:ANTV
A73D
+BFA7
DW
(:L1-1)
A73F
SYN
JS, :EOS2
A73F
+F4
DB
$80+(( ( :EOS2-*)6,$7F) XOR $40 )
A740
SYN
:RTN
A740
+03
DB
:RTN
< STATUS > =
= <
STATxEOS2>#
A741
:SSTATUS
A741
SYN
JS, :STAT
A741
+C3
DB
$80+ ( ( C :STAT-*)&$7F) XOR $40 )
A742
SYN
JS, :EOS2
A742
+F1
DB
$80+( ( ( :EOS2-*)&$7F) XOR $40 )
A743
SYN
:RTN
A743
+03
DB
:RTN
<STAT> = <
01
> , < NVAR > #
A744
:STAT
A744
SYN
JS, :D1
A744
+81
DB
$80+( ( ( :D1-*)&$7F) XOR $40 )
171
Source Code
A745
SYN
CCOM
A745 +12
DB
CCOM
A746
SYN
:ANTV,AD, :NVAR-1
A746 +00
DB
: ANTV
A747 +4BA6
DW
( :NVAR-1 )
A749
SYN
:RTN
A749 +03
DB
:RTN
< > =<STAT>,<NVARxEOS2>#
A74A
:SNOTE
A74A
:SPOINT
A74A
SYN
JS, :STAT
A74A +BA
DB
$80+(( ( :STAT-*)&$7F) XOR
$40 )
A74B
SYN
CCOM
A74B +12
DB
CCOM
A74C
SYN
: ANTV, AD, :NVAR-1
A74C +00
DB
:ANTV
A74D +4BA6
DW
( tNVAR-1)
A74F
SYN
JS, :EOS2
A74F +E4
DB
$80+( ( ( :EOS2-*)s,$7F) XOR
$40 )
A750
SYN
:RTN
A750 +03
DB
:RTN
<FS> = <STR>
A751
:FS
A751
SYN
:ANTV,AD, :STR-1
A751 +00
DB
:ANTV
A752 +81A6
DW
( :STR-1)
A754
SYN
:RTN
A754 +03
DB
:RTN
<TEXP> = <EXP>,<EXP>#
A755
TEXP
A755
SYN
:VEXP
A755 +0E
DB
:VEXP
A756
SYN
CCOM
A756 +12
DB
CCOM
A757
SYN
:VEXP
A7S7 +0E
DB
:VEXP
A758
SYN
:RTN
A758 +03
DB
:RTN
<SOUND> = <EXP>,<EXP>,
<EXP>,<EXPxEOS>#
A759
SSOUND
A759
SYN
:VEXP
A759 +0E
DB
: VEXP
A75A
SYN
CCOM
A75A +12
DB
CCOM
A75B
tSSETCOLOF
A75B
SYN
:VEXP
A75B +0E
DB
:VEXP
A75C
SYN
CCOM
A75C +12
DB
CCOM
< > =<EXP>,<EXP><EOS>#
A75D
SPOKE
A75D
SPLOT
A75D
SPOS
A75D
SDRAWTO
A75D
SYN
JS, :TEXP
A75D +B8
DB
$80+( ( ( :TEXP-*)&$7F) XOR
$40 )
A75E
SYN
JS, :EOS2
A75E +D5
DB
$80+( ( ( :EOS2-*)S,$7F) XOR
$40 )
A75F
SYN
:RTN
A75F +03
DB
: RTN
172
Source Code
<DIM> = <NSML> <EOS>#
A760
:SDIM
A760
A760
:SCOM
SYN
A760
+EC
DB
A761
SYN
A761
+D2
DB
A762
SYN
A762
+03
Dl
JS, :NSML
$80+( ( ( :NSML-*)S,$7F) XOR $40 )
JS, :E0S2
$B0+( ( ( :EOS2-*)5,$7F) XOR $40 )
:RTN
:RTN
<ON> = <EXP> <ON1><EXPLxEOS>#
A763
:SON SYN
:VEXP
A763 +0E
DB
:VEXP
A764
SYN
JS, :0N1
A764 +C4
DB
$80+( ( ( :ONl-*)£,$7F) XOR $40 )
A765
SYN
JS, :EXPL
A765 +C7
DB
$80+( ( ( :EXPL-*)S-$7F) XOR $40 )
A766
SYN
JS, :EOS2
A766 +CD
DB
$80+( ( ( :EOS2-*)&$7F) XOR $40 )
A767
SYN
:RTN
A767 +03
DB
:RTN
<ON1> =
GOTO
GOSUB#
A76S
:ONl SYN
CGTO
A768 +17
DB
CGTO
A769
SYN
:OR
A769 +02
DB
:OR
A76A
SYN
CGS
A76A +18
DB
CGS
A76B
SYN
:RTN
A76B +03
DB
:RTN
<EXPL> =
<EXPxEXPL1>#
A76C
:EXPL SYN
:VEXP
A76C +0E
DB
:VEXP
A76D
SYN
JS, :EXPL1
A76D +C2
DB
$80+( ( ( :EXPL1-*)&$7F) XOR $40
A76E
SYN
:RTN
A76E +03
DB
:RTN
<EXPL1>
= ,<EXPL> | &#
A76F
:EXPL1 SYN
CCOM
A76F +12
DB
CCOM
A770
SYN
JS, :EXPL
A770 +BC
DB
$80+( ( ( :EXPL-*)£,$7F) XOR $40 )
A771
SYN
:OR
A771 +02
DB
:OR
A772
SYN
:RTN
A772 +03
DB
:RTN
<EOS2> =
=CEOS | CCR#
A773
:E0S2
A773
SYN
CEOS
A773 +14
DB
CEOS
A774
SYN
:OR
A774 +02
DB
:OR
A775
SYN
CCR
A775 +16
DB
CCR
A776
SYN
:RTN
A776 +03
DB
:RTN
<NSMAT> = <TNVAR> ( <EXP> <NMAT2> )
A777
: NSMAT
A777
SYN
:ESRT, AD, :TNVAR-1
A777 +01
DB
:ESRT
173
Source Code
A778
+29A3
DW
( :TNVAR-1)
A77A
SYN
CLPRN, :CHNG,CDLPRN
A77A
+2B
DB
CLPRN
A77B
+0F
DB
:CHNG
A77C
+39
DB
CDLPRN
A77D
SYN
:VEXP
A77D
+0E
DB
:VEXP
A77E
SYN
:ANTV,AD, :NMAT2-1
A77E
+00
DB
:ANTV
A77F
+ 58A6
DW
( :NMAT2-1)
A781
SYN
CRPRN
A781
+2C
DB
CRPRN
A782
SYN
:0R
A782
+02
DB
:OR
A783
SYN
:ESRT, AD, :TSVAR-1
A783
+01
DB
:ESRT
A784
+2DA3
DW
( :TSVAR-1)
A786
SYN
CLPRN, :CHNG,CDSLPR
A786
+2B
DB
CLPRN
A787
+0F
DB
:CHNG
A788
+3B
DB
CDSLPR
A789
SYN
:VEXP
A789
+0E
DB
:VEXP
A78A
SYN
CRPRN
A78A
+2C
DB
CRPRN
A78B
SYN
:RTN
A78B
+03
DB
:RTN
<NSML> =
<NSMAT>
<NSML2
> | &#
A78C
:NSML SYN
JS, :NSMAT
A78C
+AB
DB
$80+(( ( :NSMAT-*)&$7F) XOR $40 )
A78D
SYN
JS, :NSML2
A78D
+C3
DB
$80+( ( ( :NSML2-*)E,$7F) XOR $40 )
A78E
SYN
:OR, :RTN
A78E
+02
DB
:OR
A78F
+03
DB
:RTN
<NSML2> =
= ,<NSML>
| &#
A790
:NSML2 SYN
CCOM
A790
+ 12
DB
CCOM
A791
SYN
JS, :NSML
A791
+BB
DB
$80+( ( ( :NSML-*)&$7F) XOR $40 )
A792
SYN
:OR, :RTN
A792
+02
DB
:OR
A793
+03
DB
:RTN
<IF>
= <EXP> THEN <
IFA><EOS>#
A794
:SIF SYN
: VEXP
A794
+0E
DB
:VEXP
A795
SYN
CTHEN
A795
+1B
DB
CTHEN
A796
SYN
JS, :IFA
A796
+C3
DB
$80+( ( ( :IFA-*)S,$7F) XOR $40 )
A797
SYN
JS, :EOS2
A797
+9C
DB
$80+( ( ( :EOS2-*)6,$7F) XOR $40 )
A798
SYN
:RTN
A798
+03
DB
:RTN
<IFA> = <TNCON> I <EIF>
A799
A799 +01
A79A +FFA3
A79C
A79C +02
A79D
A79D +01
A79E +D3A2
:ESRT, AD, :TNCON-l
DB
:ESRT
DW
( :TNCON-l )
SYN
:OR
DB
:OR
SYN
:ESRT, AD, :EIF
DB
:ESRT
DW
( :EIF-1)
174
Source Code
<PR1> = <PEL> I <PSL><PR2> | &#
:PR1
A7A0
A7A0
A7A0 +C9
A7A1 +02
A7A2
A7A2 +D4
A7A3
A7A3 +C3
A7A4
A7A4 +02
A7A5
A7A5 +03
SYN JS, :PEL, :OR
DB $80+( ( ( :PEL-*)&$7F) XOR $40 )
DB :OR
SYN JS, :PSL
DB $80+( ( ( :PSL-*)5.$7F) XOR $40 )
SYN JS, :PR2
DB $80+( ( ( :PR2-*)&$7F) XOR $40 )
SYN :OR
DB :OR
SYN : RTN
DB : RTN
<PR2> = <PEL> &#
A7A6 :PR2
A7A6 +C3
A7A7
A7A7 +02
A7A8
A7A8 +03
<PEL> = <PES> <PELA>#
: PEL
3YN
JS,
:PEL
DB
?80+(((:
:PEL-*)&$7F) XOR $40 )
SYN
:OR
DB
:OR
SYN
:RTN
DB
:RTN
A7A9
A7A9 +C3
A7AA
A7AA +C8
A7AB
A7AB +03
SYN JS, :PES
DB $80+( ( ( :PES-*)s,$7F) XOR $40 )
SYN JS, :PELA
DB $80+( ( ( :PELA-*)&$7F) XOR $40 )
SYN : RTN
DB : RTN
<PES> = <EXP> I <STR>
A7AC
:PES SYN
:VEXP
A7AC
+0E
DB
: VEXP
A7AD
SYN
:OR
A7AD
+02
DB
:OR
A7AE
SYN
: ANTV, AD, : STR-1
A7AE
+00
DB
:ANTV
A7AF
+81A6
DW
( : STR-1 )
A7B1
SYN
:RTN
A7B1
+03
DB
:RTN
<PELA> = <
PSL> <
PEL> j &#
A7B2
:PELA SYN
JS, :PSL
A7B2
+C4
DB
$80+( ( ( :PSL-*)&$7F) XOR $40 )
A7B3
SYN
JS, :PR2
A7B3
+B3
DB
$80+( ( ( :PR2-*)6,$7F) XOR $40 )
A7B4
SYN
:OR
A7B4
+02
DB
:OR
A7B5
SYN
:RTN
A7B5
+03
DB
:RTN
<PSL> = <PS> <PSLA>#
A7B6
A7B6 +C6
A7B7
A7B7 +C2
A7B8
A7B8 +03
A7B9
A7B9 +BD
A7BA
L SYN JS, :PS
DB $80+( ( ( :PS-*)&$7F) XOR $40 )
SYN JS, :PSLA
DB $80+( ( ( :PSLA-*)&$7F) XOR $40 )
SYN : RTN
DB : RTN
<PSLA> = <PSL> [ &#
:PSLA SYN JS, :PSL
DB $80+( ( (:PSL-*)6,$7F) XOR $40 )
SYN :OR
175
Source Code
A7BA
+02
A7BB
A7BB
+03
<PS>=,
A7BC
A7BC
+12
A7BD
A7BD
+02
A7BE
A7BE
+15
A7BF
A7BP
+03
< L1 > = <
A7C0
A7C0
+0E
A7C1
A7C1
+C3
A7C2
A7C2
+02
A7C3
A7C3
+03
,#
DB
:0R
SYN
:RTN
DB
:RTN
DB
CCOM
SYN
:0R
DB
:0R
SYN
CSC
DB
CSC
SYN
:RTN
DB
U 4t
:RTN
SYN
:VEXP
DB
:VEXP
SYN
JS, :L2
DB
$80+(((:L2
SYN
:OR
DB
:0R
SYN
:RTN
DB
:RTN
L2-*)&$7F) XOR ?40 )
<L2> =,<EXP> | &#
A7C4 :L2 SYN CC
A7C4 +12 DB CCOM
A7C5 SYN :VEXP
A7C5 +0E DB :VEXP
A7C6 SYN :OR
A7C6 +02 DB :OR
A7C7 SYN :RTN
A7C7 +03 DB :RTN
<REM> = <EREM>
A7C8
A7C8 +01
A7C9 +DPA2
:SREM SYN
DB :ESRT
DW ( : EREM-1 )
ESRT.AD, :EREM-1
<SDATA> = <EDATA>
A7CB
A7CB +01
A7CC +DFA2
:SDATA SYN
DB :ESRT
DW ( : EDATA-1 )
:ESRT,AD, : EDATA-1
<NFSP> =ASC | VAL | LEN#
A7CE
A7CE +40
A7CF +02
A7D0
A7D0 +41
A7D1 +02
A7D2
A7D2 +43
A7D3 +02
A7D4
A7D4 +42
A7D5
A7D5 +03
P SYN
CASC, :OR
DB
CASC
DB
:OR
SYN
CVAL, :OR
DB
CVAL
DB
:OR
SYN
CADR, :OR
DB
CADR
DB
:OR
SYN
CLEN
DB
CLEN
SYN
:RTN
DB
:RTN
176
Source Code
<SFNP> = STR | CHR#
A7D6
A7D6 +3D
A7D7 +02
A7D8
A7D8 +3E
A7D9
A7D9 +03
SFNP SYN
CSTR,
:OR
DB
CSTR
DB
:0R
SYN
CCHR
DB
CCHR
SYN
:RTN
DB
:RTN
<PUSR> = <EXP> <PUSR1>#
A7DA
PUSR SYN
:VEXP
A7DA +0E
DB
:VEXP
A7DB
SYN
JS, :PUSR1
A7DB +C2
DB
$80+( ( ( :PUSR1-*)&$7F) XOR $40
A7DC
SYN
:RTN
A7DC +03
DB
:RTN
<PUSR1> =
,<PUSR
>
| &#
A7DD
PUSR1 SYN
CCOM, :CHNG,CACOM
A7DD +12
DB
CCOM
A7DE +0F
DB
:CHNG
A7DF +3C
DB
CACOM
A7E0
SYN
JS, :PUSR
A7E0 +BA
DB
$80+(((:PUSR-*)6.$7F) XOR $40 )
A7E1
SYN
:OR
A7E1 +02
DB
:OR
A7E2
SYN
:RTN
A7E2 +03
DB
:RTN
OPNTAB — Operator Name Table
A7E3
= 000F
C
SET
$0F
A7E3
= 0010
= 0010
82
C
CDQ
DB
SET
EQU
$82
C+l
C
A7E4
= 0011
= 0011
80
C
CSOE
DB
SET
EQU
$80
C+l
C
A7E5
= 0012
» 0012
AC
C
CCOM
DC
SET
EQU
.
C+l
c
A7E6
= 0013
= 0013
A4
C
CDOL
DC
SET
EQU
'$
C+l
c
A7E7
= 0014
= 0014
BA
C
CEO£
DC
SET
EQU
i
C+l
c
A7E8
= 0015
= 0015
BB
C
CSC
DC
SET
EQU
■
C+l
c
A7E9
= 0016
= 0016
9B
C
CCR
DB
SET
EQU
CR
C+l
c
A7EA
■ 0017
= 0017
474F54CF
C
CGTC
DC
SET
EQU
'GOTO
C+l
c
,-FIRST ENTRY VALUE=$10
,- DOUBLE QUOTE
DUMMY FOR SOE
; CARRIAGE RETURN
177
Source Code
A7F3
A7F5
A7FE
A800
A806
A80C
= 0018
= 0018
474F5355C2
C
CGS
DC
SET C+l
EQU C
'GOSUB'
= 0019
= 0019
54CF
c
CTO
DC
SET
EQU
'TO'
C + l
C
= 001A
= 001A
535445D0
C
CSTEP
DC
SET
EQU
'STEP
C+l
c
= 001B
= 001B
544845CE
C
CTHF
:N
DC
SET
EQU
'THEN
C+l
C
= 001C
= 001C
A3
C
CPNC
1
DC
SET
EQU
'#'
C+l
c
= 001D
CSROP
EQU
C+l
= 001D
= 001D
3CBD
C
CLE
DC
SET
EQU
' <= '
C+l
C
= 001E
= 001E
3CBE
C
CNE
DC
SET
EQU
' <> '
C+l
C
= 001F
= 001F
3EBD
C
CGE
DC
SET
EQU
' >= '
C+l
C
= 0020
= 0020
BC
C
CLT
DC
SET
EQU
1 < '
C+l
c
= 0021
= 0021
BE
C
CGT
DC
SET
EQU
1 > '
C+l
c
= 0022
= 0022
BD
C
CEQ
DC
SET
EQU
C+l
c
= 0023
= 0023
DE
C
CEXP
DB
SET
EQU
$5E
C+l
c
+ $80
= 0024
= 0024
AA
C
CMUL
DC
SET
EQU
C+l
c
= 0025
= 0025
AB
C
CPLUS
DC
SET
EQU
'+ '
C+l
c
= 0026
= 0026
AD
Q
CMINUS
DC
SET
EQU
C+l
c
= 0027
= 0027
AF
C
CDIV
DC
SET
EQU
'/'
C+l
c
= 0028
= 0028
4E4FD4
C
CNOT
DC
SET
EQU
'NOT'
C+l
c
START OF REAL OPS
;UP ARROW FOR EXP
178
Source Code
A80F
= 0029
= 0029
4FD2
C
COR
DC
SET
EQU
'OR'
C+l
c
A811
= 002A
= 002A
414EC4
C
CAND
DC
SET
EQU
'AND'
C+l
c
A814
■ 002B
= 002B
A8
C
CLPRN
DC
SET
EQU
'( '
C+l
c
A815
= 002C
= 002C
A9
C
CRPRN
DC
SET
EQU
')'
C + l
C
A816
A817
A818
A81A
A81C
A81F
A821
A82 2
A823
THE FOLLOWING ENTRIES ARE COMPRISED OF CHARACTERS
SIMILAR TO SOME OF THOSE ABOVE BUT HAVE
DIFFERENT SYNTACTICAL OR SEMANTIC MEANING
.-ARITHMETIC ASSIGMENT
= 002D
= 002D
BD
C
CAASN
DC
SET
EQU
C + l
C
= 002E
= 002E
BD
C
CSASN
DC
SET
EQU
C+l
C
= 002F
= 002F
3CBD
C
CSLE
DC
SET
EQU
C + l
c
= 0030
= 0030
3CBE
C
CSNE
DC
SET
EQU
' <> '
C+l
c
= 0031
= 0031
3EBD
C
CSGE
DC
SET
EQU
' >= '
C+l
c
= 0032
= 0032
BC
C
CSLT
DC
SET
EQU
' < '
C+l
c
= 0033
■ 0033
BE
C
CSGT
DC
SET
EQU
' > '
C+l
c
= 0034
= 0034
BD
C
CSEQ
DC
SET
EQU
C+l
C
= 0035
= 3035
AB
C
CUPLUS
DC
SET
EQU
'+ '
C+l
c
= 0036
= 0036
AD
C
CUMINUS
DC
SET
EQU
C + l
c
= 0037
= 0037
A8
C
CSLPRN
DC
SET
EQU
'( '
C+l
c
= 0038
= 0038
80
= 0039
= 0039
C
CALPRN
DB
C
CDLPRN
SET
EQU
$80
SET
EQU
C+l
C
C + l
c
STRING OPS
; UNARY PLUS
UNARY MINUS
; STRING LEFT PAREN
; ARRAY LEFT PAREN
; DOES NOT PRINT
DIM LEFT PAREN
179
Source Code
A825
80
DB
$80
; DOES NOT PR
A826
= 003A
= 003A
A8
C
CPLPRN
DC
SET
EQU
C+l
C
; FUNCTION LE
A827
= 003B
= 003B
A8
C
CDSLPR
DC
SET
EQU
'(
,
C+l
c
A828
= 003C
= 003C
AC
C
CACOM
DC
SET
EQU
C + l
C
I ARRAY COMMA
Function Name Table
PART OF ONTAB
= 003D
C
SET C+l
= 003D
CFFUN
EQU C
= 003D
CSTR
EQU C
A829
535452A4
DC
'STR5 '
= 003E
C
SET C+l
= 003E
CCHR
EQU C
A82D
434852A4
DC
'CHR$'
= 003F
C
SET C+l
= 003F
CUSR
EQU C
A831
5553D2
DC
'USR'
= 0040
C
SET C+l
= 0040
CASC
EQU C
A834
4153C3
DC
'ASC
= 0041
C
SET C+l
= 0041
CVAL
EQU C
A837
5641CC
DC
'VAL'
= 0042
C
SET C+l
= 0042
CLEN
EQU C
A83A
4C45CE
DC
'LEN'
= 0043
C
SET C+l
= 0043
CADR
EQU C
A83D
4144D2
DC
'ADR'
= 0044
C
SET C+l
= 0044
CNFNP
EQU C
A840
4154CE
DC
'ATN'
A843
434FD3
DC
'COS'
A846
504545CB
DC
'PEEK'
A84A
5349CE
DC
'SIN'
A84D
524EC4
DC
'ROT'
A850
4652C5
DC
'FRE'
A853
4558D0
DC
'EXP'
A856
4C4FC7
DC
'LOG'
A859
434C4FC7
DC
' CLOG '
A85D
5351D2
DC
'SQR'
A860
S347CE
DC
'SGN'
A863
4142D3
DC
'ABS '
A866
494ED4
DC
'INT'
A869
504144444C
C5
DC
' PADDLE '
A86F
53544943CB
DC
'STICK'
A874
50545249C7
DC
'PTRJG '
A879
53545249C7
DC
'STRIG '
A87E
00
DB
500
;
END OF OPNTAB S. FNTAB
;FIRST FUNCTION CODE
;USR FUNCTION CODE
180
Source Code
Memory Manager
A87F
MEMORY MANAGEMENT CONSISTS OF EXPANDING AND
CONTRACTING TO INFORMATION AREA POINTED TO
BY THE ZERO PAGE POINTER TABLES. ROUTINES
MODIFY THE ADDRESS IN THE TABLES AND
MOVE DATA AS REQUIRED. THE TWO FUNDAMENTAL
ROUTINES ARE 'EXPAND' AND 'CONTRACT'
EXPAND
X = ZERO PAGE ADDRESS OF TABLE AT WHICH
EXPANSION IS TO START
Y = EXPANSION SIZE IN BYTES [LOW]
A = EXPANSION SIZE IN BYTES [HIGH]
EXPLOW - FOR EXPANSION < 256 BYTES
SETS A =
A87F
A900
EXPLOW LDA
#0
A881
EXPAND
A881
84A4
STY
ECSIZE
A883
85A5
STA
ECSIZE+1
A885
38
SEC
A886
A590
LDA
MEM TOP
A888
65A4
ADC
ECSIZE
A88A
A8
TAY
A88B
A591
LDA
MEMTOP+1
A88D
65A5
ADC
ECSIZE+1
A88F
CDE602
CMP
HIMEM+1
A892
900C "A8A0
BCC
:EXP2
A894
D007 "A89D
BNE
:EXP1
A896
CCE502
CPY
HIMEM
A899
9005 ~A8A0
BCC
:EXP2
A89B
F003 "A8A0
BEQ
:EXP2
A89D
4C3CB9
:EXP1 JMP
MEMFULL
A8A0
iEXP2
A8A0
38
SEC
A8A1
A590
LDA
MEMTOP
A8A3
F500
SBC
0,X
A8A5
85A2
STA
MVLNG
A8A7
A591
LDA
MEMTOP+1
A8A9
F501
SBC
1,X
A8AB
85A3
STA
MVLNG+1
A8AD
18
CLC
A8AE
7501
ADC
1,X
A8B0
859A
STA
MVFA+1
A8B2
B500
LDA
0,X
A8B4
8599
STA
MVFA
A8B6
8597
STA
SVESA
A8B8
65A4
ADC
ECSIZE
A8BA 859B
A8BC
B501
A8BE
8598
A8C0
65A5
A8C2
6 5A3
A8C4
859C
LDA
1,X
STA
SVESA+1
ADC
ECSIZE+1
ADC
MVLNG+1
STA
MVTA+1
SAVE EXPAND SIZE
TEST MEMORY TO BE FULL
MEMTOP+ECSIZE+1
MUST BE LE
HIMEM
FORM MOVE LENGTH [MVLNG]
MOVE FROM ADR [MVFA]
MVLNG = MEMTOP-EXPAND ADR
MVFA[L] = EXP ADR [L]
MVFA[H] = EXP ADR[H] +
MVLNG[H]
DURING MOVE MVLNG[L]
WILL BE ADDED SUCH
THAT MVFA = MEMTOP
SAVE PREMOVE EXPAND AT VALUE
SET MVFA LOW
FORM MOVE TO ADR [MVTA]
MVTA[L] = EXP ADR[L] +
ECSIZE[L]
MVTA[H] = [CARRY + EXP
AD-[H]
+ECSIZE[H]] + MVLNG[H]
DURING MOVE MVLNG[L]
WILL BE ADDED SUCH THAT
MVTA = MEMTOP + ECSIZE
181
Source Code
A8C6
A8C8
A8CA
A8CC
A8CE
A8D0
A8D2
A8D3
A8D4
A8D6
A8D8
A8DA
A8DC
A8DE
A8E0
B500
65A4
9500
B501
65A5
9501
E8
E8
E092
90EE
850F
A590
850E
A6A3
E8
A8E1 A4A2
A8E3 D00B
A8E5 F010
'A8F0
'A8F7
LDA
0,X
ADC
ECSIZE
STA
0,X
LDA
1,X
ADC
ECSIZE+1
STA
1,X
I NX
I NX
CPX
#MEMTOP+2
BCC
:EXP3
STA
APHM+1
LDA
MEMTOP
STA
APHM
LDX
MVLNG+1
INX
LDY
MVLNG
BNE
:EXP6
BEQ
:EXP7
ADD ECSIZE TO
ALL TABLE ENTRIES
FROM EXPAND AT ADR
TO HIMEM
SET NEW APL
HI MEM TO
MEMTOP
X = MVLNG[H]
PLUS ONE
Y = MVLNG[L]
TEST ZERO LENGTH
BR IF LOW =
A8E7 88
A8E8 C69A
A8EA C69C
:EXP4 DEY
DEC MVFA+1
DEC MVTA+1
DEC MVLNG [L]
DEC MVFA[H]
DEC MVTA[H]
A8EC B199
A8EE 91 9B
A8F0 88
A8F1 D0F9 "A8EC
:EXP5 LDA [MVFA],Y
STA [MVTA],Y
:EXP6 DEY
BNE :EXP5
MVFA BYTE
TO MVTA
DEC COUNT LOW
BR IF NOT ZERO
A8F3 B199
A8F5 919B
LDA
STA
[MVFA],Y
[MVTA],Y
MOVE THE ZERO BYTE
A8F7 :EXP7
A8F7 CA DEX
A8F8 D0ED "A8E7 BNE
A8FA 60 RTS
:EXP4
IF MVLNG[H] IS NOT
ZERO THEN MOVE 256 MORE
ELSE
DONE
CONTRACT
A8FB A900
A8FD
A8FD
84A4
A8FF
85A5
A901
38
A902
A590
A904
F500
A906
49FF
A908
A8
A909
C8
A90A
84A2
A90C
A591
A90E
F501
A910
85A3
A912
B500
A914
E5A2
A916
8599
A918
B501
; CONTLOW
!
SETS
CONTLOW LDA #0
CONTRACT
STY
ECSIZE
STA
ECSIZE+1
SEC
LDA
MEMTOP
SBC
0,X
EOR
#?FF
TAY
INY
STY
MVLNG
LDA
MEMTOP+1
SBC
1,X
STA
MVLNG+1
LDA
0,X
SBC
MVLNG
STA
MVFA
LDA
1,X
X = ZERO PAGE ADR OF TABLE AT WHICH
CONTRACTION WILL START
Y = CONTRACT SIZE IN BYTES [LOW]
A = CONTRACT SIZE IN BYTES [HI]
SAVE CONTRACT SIZE
FORM MOVE LENGTH [LOW]
MVLNG[L] = $100-
[MEMTOP[L]] - CON AT
VALUE [L]
THIS MAKES START Y AT
MOVE HAVE A 2 ' S COMPLEMENT
REMAINDER IN IT
FORM MOVE LENGTH[HIGH]
FORM MOVE FROM ADR [MVFA]
MVFA = CON AT VALUE
MINUS MVLNG[L]
DURING MOVE MVLNG[L]
182
Source Code
A91A E900
A91C 859A
A91E 869B
SBC
STA
#0
MVFA+1
WILL BE ADDED BACK INTO
MVFA IN [IND],Y INST
TEMP SAVE OF CON AT DISPL
A920
38
:CONTl
SEC ; SUB
A921
B500
LDA
0,X
A923
E5A4
SBC
ECSIZE
A925
9500
STA
0,X
A92 7
B501
LDA
1,X
A929
E5A5
SBC
ECSIZE+1
A92B
9501
STA
1,X
A92D
E8
INX
A92E
E8
INX
A92F
E092
CPX
#MEMTOP+2
A931
90ED
~A920
BCC
:CONTl
A933
850F
STA
APHM+1
A935
A590
LDA
MEMTOP
A937
850E
STA
APHH
A939
A69B
LDX
MVTA
A93B
B500
LDA
0,X
A93D
E5A2
SBC
MVLNG
A93F
859B
STA
MVTA
A941
B501
LDA
1,X
A943
E900
SBC
#0
A945
859C
STA
MVTA+1
A947
FMOVER
A947
A6A3
LDX
MVLNG+1
A949
E8
INX
A94A
A4A2
LDY
MVLNG
A94C
D006
"A954
BNE
:CONT2
A94E
F00B
"A95B
BEQ
: CONT4
A950
E69A
:CONT3
INC MVFA+
A952
E69C
INC
MVTA+1
A954
B199
:CONT2
LDA [MVFA
A956
91 9B
STA
[MVTA],Y
A958
C8
INY
A959
D0F9
"A954
BNE
:CONT2
A95B
:CONT4
A95B
CA
DEX
A95C
D0F2
"A950
BNE
:CONT3
A95E
60
RTS
SUBTRACT ECSIZE FROM
ALL TABLE ENTRY FROM
CON AT ADR TO HIMEM
SET NEW APL
HI MEM TO
MEMTOP
FORM MOVE TO ADR [MVTA]
MVTA = NEW CON AT VALUE
MINUS MVLNG [L]
DURING MOVE MVLNG[L]
WILL BE ADDED BACK INTO
MVTA IN [INO],Y INST
GET MOVE LENGTH HIGH
INC SO MOVE CAN BNE
GET MOVE LENGTH LOW
IF NOT ZERO GO
BR IF LOW =
;INC MVFA[H]
; INC MVTA[H]
GET MOVE FROM BYTE
SET MOVE TO BYTE
INCREMENT COUNT LOW
BR IF NOT ZERO
DECREMENT COUNT HIGH
BR IF NOT ZERO
ELSE DONE
Execute Control
A95F LOCAL
EXECNL — Execute Next Line
START PROGRAM EXECUTOR
A95F
A95F 201BB8
EXECNL
JSR
EXECNS — Execute Next Statement
SET UP LIN & NXT STMT
A962
EXECNS
A962
20F4A9
JSR
TSTBRK
A965
D035 "A99C
BNE
:EXBRK
A967
A4A7
LDY
NXTSTD
A969
C49F
CPY
LLNGTH
A96B
B01C "A989
BCS
:EXEOL
TEST BREAK
BR IF BREAK
GET PTR TO NEXT STMT L
AT END OF LINE
BR IF EOL
183
Source Code
A96D
B18A
A96F
85A7
A971
98
A972
C8
A973
B18A
A975
C8
A976
84A8
A978
207EA9
A97B
4C62A9
A97E
A97E +0A
A97F AA
A980
A983
A984
A987
A988
BD00AA
48
BD01AA
48
60
LDA
STA
TYA
I NY
LDA
I NY
STY
JSR
JMP
ASL
TAX
LDA
PHA
LDA
PHA
RTS
[STMCUR], Y
NXTSTD
[STMCUR], Y
STINDEX
:STGO
EXECNS
STETAB.X
STETAB+l.X
GET NEW STMT LENGTH
SAVE AS FUTURE STMT LENGTH
Y=DISPL TO THIS STMT LENGTH
PLUS 1 IS DISPL TO CODE
GET CODE
INC TO STMT MEAT
SET WORK INDEX
GO EXECUTE
THEN DO NEXT STMT
GET ADR AND
PUSH TO STACK
AND GO TO
VIA
RTS
A989 :EXEOL
A989 A001 LDY #1
A98B B18A LDA [STMCUR], Y
A98D 3010 "A99F BMI :EXFD
BR IF DIR
A98F A59F
A991 20D0A9
A994 20E2A9
A997 10C6 "A95F
A999 4C8DB7
A99C 4C93B7
A99F 4C5DA0
LDA
JSR
JSR
BPL
EXDONE JMP
EXBRK JMP
EXFD JMP
LLNGTH
GNXTL
TENDST
EXECNL
XEND
XSTOP
SNX3
;GET LINE LENGTH
;INC STMCUR
;TEST END STMT TABLE
;BR NOT END
; GO BACK TO SYNTAX
; BREAK, DO STOP
! GO TO SYNTAX VIA READY MSG
GETSTMT — Get Statement in Statement Table
SEARCH FOR STMT THAT HAS TSLNUM
SET STMCUR TO POINT TO IT IF FOUND
OR TO WHERE IT WOULD GO IF NOT FOUND
CARRY SET IF NOT FOUND
GETSTMT
SAVE CURRENT LINE ADDR
A9A2
A9A4
A9A6
A9A8
A9AA
A9AC
A58A
85BE
A58B
85BF
A589
A488
LDA
STA
LDA
STA
LDA
LDY
STMCUR
SAVCUR
STMCUR+1
SAVCUR+1
STMTAB+1
STMTAB
; START AT TOP OF TABLE
A9AE 858B
A9B0 848A
A9B2
A9B4
A9B6
A9B8
A9BA
A9BC
A9BD
A9BF
A9C1
A9C3
A9C5
A9C6
A9C6
A001
B18A
C5A1
900D
D00A
88
B18A
C5A0
9004
D001
18
60
"A9C7
'A9C6
A9C7
'A9C6
A9C7 20DDA9
STA
STY
GS2
LDA
CMP
BCC
BNE
DEY
LDA
CMP
BCC
BNE
CLC
:GSRT1
RTS
:GS3
STMCUR+1
STMCUR
#1
[STMCUR], Y
TSLNUM+1
GS3
GSRT1
GS3
[STMCUR], Y
TSLNUM
:GS3
:GSRT1
;SET STMCUR
GET STMT LNO [HI]
TEST WITH TSLNUM
BR IF S<TS
BR IF S>TS
S=TS, TEST LOW BYTE
;BR S<TS
;BR S>TS
;S=TS, CLEAR CARY
;AND RETURN [FOUND]
;GO GET THIS GUYS LENGTH
184
Source Code
A9CA
20D0A9
JSR
GNXTL
A9CD
A9D0
4CB2A9
JMP
GNXTL
:GS2
A9D0
18
CLC
A9D1
658A
ADC
STMCUR
A9D3
858A
STA
STMCUR
A9D5
A8
TAY
A9D6
A58B
LDA
STMCUR+1
A9D8
6900
ADC
#0
A9DA
858B
STA
STMCUR+1
A9DC
60
RTS
A9DD
A002
GETLL LDY #2
A9DF
B18A
LDA
[STMCUR], Y
A9E1
60
RTS
;ADD LENGTH TO STMCUR
TENDST — Test End of Statement Table
A9E2
TENDST
A9E2
A001
LDY
#1
A9E4
B18A
LDA
[STMCUR], Y
A9E6
60
RTS
A9E7
XREM
A9E7
XDATA
A9E7
60
TESTRTS
RTS
INDEX TO CNO [ 'I]
GET CNO [HI]
XBYE — Execute BYE
8
XBYE
8
2041BD
JSR
CLSALL
B
4C71E4
JMP
BYELOC
CLOSE 1-7
EXIT
XDOS — Execute DOS
A9EE
2041BD
A9P1
6C0A00
TSTBR
A9F4
K — Tes
A9F4
A000
A9F6
A511
A9F8
D004 "
A9FA
A0FF
A9FC
8411
A9FE
98
A9FF
60
JSR
CLSALL
JMP
[DOSLOC]
eak
TSTBRK
LDY
#0
LDA
BRKBYT
BNE
:TB2
LDY
#?FF
STY
BRKBYT
:TB2
TYA
RTS
CLOSE 1-7
GO TO DOS
; LOAD BREAK BYTE
SET COND CODE
DONE
Statement Execution Table
STETAB-STATEMENT EXECUTION TABLE
-CONTAINS STMT EXECUTION ADR
-MUST BE IN SAME ORDER AS SNTAB
AA00
STETAB
AA00
FDB
XREM-1
AA00
+A9E6
DW
REV (XREM-1 )
AA02
FDB
XDATA-1
AA02
+A9E6
DW
REV (XDATA-1 )
= 0001
CDATA
EQU
(*-STETAB)/2-
-1
AA04
FDB
XINPUT-1
AA04
AA06
+B315
DW
FDB
REV (XINPUT-1)
XCOLOR-1
AA06
+BA28
DW
REV (XCOLOR-1 )
AA08
FDB
XLIST-1
AA08
+B482
DW
REV (XLIST-1)
= 0004
CLIST
EQU
(*-STETAB) /2
-1
185
Source Code
AA0A
FDB
XENTER-1
AA0A
+BACA
DW
REV (XENTER-1)
AA0C
FDB
XLET-1
AA0C
+AADF
DW
REV (XLET-1 )
AA0E
FDB
XIF-1
AA0E
+B777
DW
REV (XIF-1)
AA10
FDB
XFOR-1
AA10
+B64A
DW
REV (XFOR-1)
= 0008
CFOR
EQU (*-STETAB)/2-l
AA12
FDB
XNEXT-1
AA12
+B6CE
DW
REV (XNEXT-1 )
AA14
FDB
XGOTO-1
AA14
+B6A2
DW
REV (XGOTO-1 )
AA16
FDB
XGOTO-1
AA16
+B6A2
DW
REV (XGOTO-1)
AA18
FDB
XGOSUB-1
AA18
+B69F
DW
REV (XGOSUB-1)
= 000C
CGOSUB
EQU (*-STETAB)/2-l
AA1A
FDB
XTRAP-1
AA1A
+B7E0
DW
REV (XTRAP-1)
AA1C
FDB
XBYE-1
AA1C
+A9E7
DW
REV (XBYE-1)
AA1E
FDB
XCONT-1
AA1E
+B7BD
DW
REV (XCONT-1 )
AA20
FDB
XCOM-1
AA20
+B1D8
DW
REV (XCOM-1)
AA22
FDB
XCLOSE-1
AA22
+BC1A
DW
REV (XCLOSE-1)
AA24
FDB
XCLR-1
AA24
+B765
DW
REV (XCLR-1 )
AA26
FDB
XDEG-1
AA26
+B260
DW
REV (XDEG-1)
AA28
FDB
XDIM-1
AA28
+B1D8
DW
REV (XDIM-1)
AA2A
FDB
XEND-1
AA2A
+B78C
DW
REV (XEND-1)
AA2C
FDB
XNEW-1
AA2C
+A00B
DW
REV (XNEW-1)
AA2E
FDB
XOPEN-1
AA2E
+BBEA
DW
REV (XOPEN-1)
AA30
FDB
XLOAD-1
AA30
+BAFA
DW
REV (XLOAD-1 )
AA32
FDB
XSAVE-1
AA32
+BB5C
DW
REV (XSAVE-1 )
AA34
FDB
XSTATUS-1
AA34
+BC27
DW
REV (XSTATUS-1)
AA36
FDB
XNOTE-1
AA36
+BC35
DW
REV (XNOTE-1 )
AA38
FDB
XPOINT-1
AA38
+BC4C
DW
REV (XPOINT-1)
AA3A
FDB
XXIO-1
AA3A
+BBE4
DW
REV (XXIO-1)
AA3C
FDB
XON-1
AA3C
+B7EC
DW
REV (XON-1)
= 001E
CON
EQU (*-STETAB)/2-l
AA3E
FDB
XPOKE-1
AA3E
+B24B
DW
REV (XPOKE-1)
AA40
FDB
XPRINT-1
AA40
+B3B5
DW
REV (XPRINT-1)
AA42
FDB
XRAD-1
AA42
+B265
DW
REV (XRAD-1)
AA44
FDB
XREAD-1
AA44
+B282
DW
REV (XREAD-1)
= 0022
CREAD
EQU (*-STETAB)/2-l
AA46
FDB
XREST-1
AA46
+B26A
DW
REV (XREST-1)
AA48
FDB
XRTN-1
AA4B
+B718
DW
REV (XRTN-1)
AA4A
FDB
XRUN-1
AA4A
+B74C
DW
REV (XRUN-1)
AA4C
FDB
XSTOP-1
186
Source Code
AA4C
+B792
DW
REV (XSTOP-1)
AA4E
PDB
XPOP-1
AA4E
+B840
DW
REV (XPOP-1)
AA50
FDB
XPRINT-1
AA50
+B3B5
DW
REV (XPRINT-1)
AA52
FDB
XGET-1
AA52
+BC7E
DW
REV (XGET-1 )
AA54
FDB
XPUT-1
AA54
+BC71
DW
REV (XPUT-1)
AA56
FDB
XGR-1
AA56
+BA4P
DW
REV (XGR-1)
AA58
FDB
XPLOT-1
AA58
+BA75
DW
REV (XPLOT-1 )
AA5A
FDB
XPOS-1
AA5A
+BA15
DW
REV (XPOS-1 )
AA5C
FDB
XDOS-1
AA5C
+A9ED
DW
REV (XDOS-1 )
AA5E
FDB
XDRAWTO-1
AA5E
+BA30
DW
REV (XDRAWTO-1)
AA60
FDB
XSETC0L0R-1
AA60
+B9B6
DW
REV (XSETC0L0R-1 )
AA62
FDB
XLOCATE-1
AA62
+BC94
DW
REV (XLOCATE-1 )
AA64
FDB
XSOUND-1
AA64
+B9DC
DW
REV (XSOUND-1 )
AA66
FDB
XLPRINT-1
AA66
+B463
DW
REV (XLPRINT-1)
AA68
FDB
XCSAVE-1
AA68
+BBA3
DW
REV (XCSAVE-1)
AA6A
FDB
XCLOAD-1
AA6A
+BBAB
DW
REV (XCLOAD-1)
AA6C
FDB
XLET-1
AA6C
+AADF
DW
REV (XLET-1 )
= 0036
CILET
EQU (*-STETAB)/2-l
AA6E
FDB
XERR-1
AA6E
+B91D
DW
REV (XERR-1)
= 0037
CERR
EQU (*-STETAB)/2-l
Operator Execution Table
OPETAB - OPERATOR EXECUTION TABLE
- CONTAINS OPERATOR EXECUTION ADR
- MUST BE IN SAME ORDER AS OPNTAB
AA70
OPETAB
AA70
FDB
XPLE-1
AA70
+ACB4
DW
REV (XPLE-1)
AA72
FDB
XPNE-1
AA72
+ACBD
DW
REV (XPNE-1)
AA74
FDB
XPGE-1
AA74
+ACD4
DW
REV (XPGE-1 )
AA76
FDB
XPLT-1
AA76
+ACC4
DW
REV (XPLT-1 )
AA78
FDB
XPGT-1
AA78
+ACCB
DW
REV (XPGT-1 )
AA7A
FDB
XPEQ-1
AA7A
+ACDB
DW
REV (XPEQ-1 )
AA7C
FDB
XPPOWER-1
AA7C
+B164
DW
REV (XPPOWER-1)
AA7E
FDB
XPMUL-1
AA7E
+AC95
DW
REV (XPMUL-1 )
AA80
FDB
XPPLUS-1
AA80
+AC83
DW
REV (XPPLUS-1 )
AA82
FDB
XPMINUS-1
AA82
+AC8C
DW
REV (XPMINUS-1)
AA84
FDB
XPDIV-1
AA84
+AC9E
DW
REV (XPDIV-1)
AA86
FDB
XPNOT-1
AA86
+ACF8
DW
REV (XPNOT-1 )
AA88
FDB
XPOR-1
AA88
+ACED
DW
REV (XPOR-1 )
187
Source Code
AA8A
AA8A
+ACE2
AA8C
AA8C
+AB1E
AA8E
AA8E
+AD7A
AA90
AA90
+AD5E
AA92
AA92
+AEA2
AA94
AA94
+ACB4
AA96
AA96
+ACBD
AA98
AA98
+ACD4
AA9A
AA9A
+ACC4
AA9C
AA9C
+ACCB
AA9E
AA9E
+ACDB
AAA0
AAA0
+ACB3
AAA2
AAA2
+ACA7
AAA4
AAA4
+AE25
AAA6
AAA6
+AD85
AAA8
AAA8
+AD81
AAAA
AAAA
+AD7A
AAAC
AAAC
+AD81
AAAE
AAAE
+AD78
AAB0
AAB0
+B048
AAB2
AAB2
+B066
AAB4
AAB4
+B0B9
AAB6
AAB6
+B011
AAB8
AAB8
+AFFF
AABA
AABA
+AFC9
AABC
AABC
+B01B
AABE
AABE
+B12E
AAC0
AAC0
+B124
AAC2
AAC2
+AFE0
AAC4
AAC4
+B11A
AAC6
AAC6
+B08A
AAC8
AAC8
+AFEA
AACA
AACA
+B14C
AACC
AACC
+B138
AACE
AACE
+B142
FDB
XPAND-1
DW
REV (XPAND-1 )
FDB
XPLPRN-1
DW
REV (XPLPRN-1)
FDB
XPRPRN-1
DW
REV (XPRPRN-1)
FDB
XPAASN-1
DW
REV (XPAASN-1)
FDB
XSAASN-1
DW
REV (XSAASN-1 )
FDB
XPSLE-1
DW
REV (XPSLE-1 )
FDB
XPSNE-1
DW
REV (XPSNE-1)
FDB
XPSGE-1
DW
REV (XPSGE-1)
FDB
XPSLT-1
DW
REV (XPSLT-1)
FDB
XPSGT-1
DW
REV (XPSGT-1 )
FDB
XPEQ-1
DW
REV (XPEQ-1)
FDB
XPUPLUS-1
DW
REV (XPUPLUS-1)
FDB
XPUMINUS-1
DW
REV (XPUMINUS-1)
FDB
XPSLPRN-1
DW
REV (XPSLPRN-1 )
FDB
XPALPRN-1
DW
REV (XPALPRN-1)
FDB
XPDLPRN-1
DW
REV (XPDLPRN-1)
FDB
XPFLPRN-1
DW
REV (XPFLPRN-1)
FDB
XDPSLP-1
DW
REV (XDPSLP-1 )
FDB
XPACOM-1
DW
REV (XPACOM-1)
FDB
XPSTR-1
DW
REV (XPSTR-1)
FDB
XPCHR-1
DW
REV (XPCHR-1)
FDB
XPUSR-1
DW
REV (XPUSR-1)
FDB
XPASC-1
DW
REV (XPASC-1)
FDB
XPVAL-1
DW
REV (XPVAL-1)
FDB
XPLEN-1
DW
REV (XPLEN-1)
FDB
XPADR-1
DW
REV (XPADR-1)
FDB
XPATN-1
DW
REV (XPATN-1)
FDB
XPCOS-1
DW
REV (XPCOS-1)
FDB
XPPEEK-1
DW
REV (XPPEEK-1)
FDB
XPSIN-1
DW
REV (XPSIN-1)
FDB
XPRND-1
DW
REV (XPRND-1)
FDB
XPFRE-1
DW
REV (XPFRE-1)
FDB
XPEXP-1
DW
REV (XPEXP-1)
FDB
XPLOG-1
DW
REV (XPLOG-1)
FDB
XPL10-1
DW
REV (XPL10-1)
188
Source Code
AAD0
AAD0
AAD2
AAD2
AAD4
AAD4
AAD6
AAD6
AAD8
AAD8
AADA
AADA
AADC
AADC
AADE
AADE
+B156
+AD18
+B0AD
+B0DC
+B021
+B025
+B029
+B02D
FDB
XPSQR-1
DW
REV (XPSQR-1)
FDB
XPSGN-1
DW
REV (XPSGN-1 )
FDB
XPABS-1
DW
REV (XPABS-1)
FDB
XPINT-1
DW
REV (XPINT-1 )
FDB
XPPDL-1
DW
REV (XPPDL-1)
FDB
XPSTICK-1
DW
REV (XPSTICK-1)
FDB
XPPTRIG-1
DW
REV (XPPTRIG-1 )
FDB
XPSTRIG-1
DW
REV (XPSTRIG-1)
Execute Expression
EXEXPR — Execute Expression
AAE0
XLET
AAE0
EXEXPR
AAE0
202EAB
JSR
EXP I NT
AAE3
: EXNXT
AAE3
203EAB
JSR
:EGTOKEN
AAE6
B006 "AAEE
BCS
:EXOT
AAE8
20BAAB
JSR
ARGPUSH
AAEB
4CE3AA
JMP
: EXNXT
AAEE
85AB
:EXOT STA
EXSVOP
AAF0
AA
TAX
AAF1
BD2FAC
LDA
0PRTAB-16,X
AAF4
LSRA
AAF4
+4A
LSR
A
AAF5
LSRA
AAF5
+4A
LSR
A
AAF6
LSRA
AAF6
+4A
LSR
A
AAF7
LSRA
AAF7
+4A
LSR
A
AAF8
8 5 AC
STA
EXSVPR
AAFA
A4A9
:EXPTST LDY
OPSTKX
AAFC
B180
LDA
[ARGSTK], Y
AAFE
AA
TAX
AAFF
BD2FAC
LDA
OPRTAB-16.X
AB02
290F
AND
#$0F
AB04
C5AC
CMP
EXSVPR
AB06
900D ~AB15
BCC
:EOPUSH
AB08
AA
TAX
AB09
F014 "AB1F
BEQ
:EXEND
AB0B
EXOPOP
AB0B
B180
LDA
[ARGSTK], Y
AB0D
E6A9
INC
OPSTKX
AB0F
2020AB
JSR
:EXOP
AB12
4CFAAA
JMP
:EXPTST
AB15
A5AB
:EOPUSH LDA
EXSVOP
AB17
88
DEY
AB18
9180
STA
[ ARGSTK ],Y
AB1A
B4A9
STY
OPSTKX
ABIC
4CE3AA
JMP
: EXNXT
AB1F
XPLPRN
GO GET TOKEN
BR IF OPERATOR
PUSH ARG
GO FOR NEXT TOKEN
SAVE OPERATOR
GET OP PREC
SHIFT FOR GOES ON TO PREC
SAVE GOES ON PREC
GET OP STACK INDEX
GET TOP OP
GET TOP OP PREC
[TOP OP]: [NEW OP]
IF T<N, PUSH NEW
ELSE POP
IF POP SOE
THEN DONE
RE-GET TOS OP
DEC OP STACK INDEX
GET EXECUTE OP
GO TEST OP WITH NEW TOS
GET OP TO PUSH
DEC TO NEXT ENTRY
SET OP IN STACK
SAVE NEW OP STACK INDEX
GO GET NEXT TOKEN
189
Source Code
AB1F
60
: EXEND RTS
DONE EXECUTE EXPR
AB20
:EXOP
AB20
38
SEC
SUBSTRACT FOR REL
AB21
E91D
SBC
#CSROP
VALUE OF FIRST REAL OP
AB23
AS LA
VALUE * 2
AB23
+0A
ASL
A
AB24
AA
TAX
AB25
BD70AA
LDA
OPETAB.X
PUT OP EXECUTION
AB28
48
PHA
ROUTINE ON STACK
AB29
BD71AA
LDA
0PETAB+1,X
AND GOTO
AB2C
48
PHA
VIA
AB2D
60
RTS
RTS
Initialize Expression Parameters
AB2E
AB2E
AB30
AB32
AB34
AB36
AB37
AB39
AB3B
AB3D
A0FF
A911
9180
84A9
C8
84B0
84AA
84B1
60
EXP I NT
LDY
LDA
STA
STY
I NY
STY
STY
STY
RTS
#$FF
#CSOE
[ARGSTK],Y
OPSTKX
COMCNT
ARSTKX
ADFLAG
GETTOK — Get Next Token and Classify
AB3E
AB3E
AB3E
AB40
AB42
AB44
A4A8
E6A8
B18A
3043 "AB89
GETTOK
rEGTOKEN
LDY
INC
LDA
BMI
STINDEX
ST INDEX
[STMCUR],Y
: EGTVAR
OPERATOR
STACK
AND INITIALIZE
ARG STACK
ASSIGN FLAG
GET STMT INDEX
INC TO NEXT
GET TOKEN
BR IF VAR
AB46 C90F
AB48 9003 "AB4D
AB4A F013 "AB5F
AB4C 60
CMP #?0F
BCC : EGNC
BEQ :EGSC
RTS
TOKEN: $0F
BR IF $0E, NUMERIC CONST
BR IF $0F, STR CONST
RTN IF OPERATOR
AB4D
AB4D
A200
AB4F
C8
AB50
B18A
AB52
95D4
AB54
E8
AB55
E006
AB57
90F6
AB59
C8
AB5A
A900
AB5C
AA
AB5D
F022
AB5F
C8
AB60
B18A
AB62
A28A
AB64
AB64
85D6
AB66
85D8
AB68
C8
AB69
98
AB6A
18
AB6B
7500
AB6D
85D4
AB6F
A900
AB71
85D7
AB73
85D9
AB75
7501
AB77
85D5
"AB4F
NCTOFR0
: EGNC LDX
:EGT1 INY
LDA
STA
I NX
CPX
BCC
INY
LDA
TAX
BEQ
:EGSC
LDA
LDX
RISC
STA
STA
INY
TYA
CLC
ADC
STA
LDA
STA
STA
ADC
STA
[STMCUR], Y
FR0.X
#6
:EGT1
tEVSCALER
[STMCUR], Y
ISTMCUR
VTYPE+EVSLEN
VTYPE+EVSDIM
0,X
VTYPE+EVSADR
#0
VTYPE+EVSLEN+1
VTYPE+EVSDIM+1
1,X
VTYPE+EVSADR+1
INC LINE INDEX
GET VALUE FROM STMT TBL
AND PUT INTO FR0
INY Y BEYOND CONST
ACU=SCALER
X = VAL NO
GO SET REM
INC Y TO LENGTH BYTE
GET LENGTH
POINT TO SMCUR
SET AS LENGTH
AND DIM
ACU=DISPL TO STR
DISPL PLUS ADR
IS STR ADR
SET =
LENGTH HIGH
DIM HIGH
FINISH ADR
190
Source Code
AB79
98
AB7A
65D6
AB7C
A8
AB7D
A200
AB7F
A983
AB81
85D2
AB83
86D3
AB85
84A8
AB87
18
AB88
60
AB89
AB89
AB89
2028AC
AB8C
B19D
AB8E
99D200
AB91
C8
AB92
C008
AB94
90F6 "i
AB96
18
AB97
60
TYA
ACU=DISPL TO STR
ADC
VTYPE+EVSLEN
PLUS STR LENGTH
TAY
IS NEW INDEX
LDX
#00
VAR NO =
LDA
#EVSTR+EVSDTA+EVDIM ; TYPE = STR
:EGST
STA
VTYPE
SET TYPE
STX
VNUM
SET NUM
STY
STINDEX
SET NEW INDEX
CLC
INDICATE VALUE
:EGRTS
RTS
RETURN
GETVAR
: EGTVAR
JSR
GWTADR
GET WT ADR
:EGT2
LDA
[WWTPT]
Y
; MOVE WT ENT
STA
VTYPE, Y
TO FR0
I NY
CPY
#8
BCC
:EGT2
CLC
INDICATE VALUE
RTS
RETURN
AAPSTR — Pop String Argument and Make Address Absolute
AB98 20F2AB
AAPSTR JSR
| GO POP ARG
GSTRAD — Get String [ABS] Address
AB9B
GSTRAD
AB9B
A902
LDA
#EVSDTA
LOAD TRANSFORMED BIT
AB9D
24D2
BIT
VTYPE
TEST STRING ADR TRANSFORM
AB9F
D015
"ABB6
BNE
: GSARTS
BR IF ALREADY TRANSFORMED
ABA1
05D2
ORA
VTYPE
TURN ON TRANS BIT
ABA 3
85D2
STA
VTYPE
AND SET
ABA 5
RORA
SHIFT DIM BIT TO CARRY
ABA 5
+6A
ROR
A
ABA 6
900F
~ABB7
BCC
:GSND
ABA 8
18
CLC
ABA 9
A5D4
LDA
VTYPE+EVSADR
STRING ADR " STRING DISPL
+ STARP
ABAB
658C
ADC
STARP
ABAD
85D4
STA
VTYPE+EVSADR
ABAF
A8
TAY
ABB0
A5D5
LDA
VTYPE+EVSADR+1
ABB2
658D
ADC
STARP+1
ABB4
85D5
STA
VTYPE+EVSADR+1
ABB6
60
: GSARTS
RTS
ABB7
202EB9
:GSND
JSR
ERRDIM
ARGPUSH — Push FRO to Argument Stack
ABBA
E6AA
ABBC
A5AA
ABBE
ABBE
+0A
ABBF
ABBF
+0A
ABC0
ABC0
+0A
ABC1
C5A9
ABC 3
B00D
ABC 5
A8
ABC 6
88
ABC 7
A207
ABC 9
B5D2
ABCB
9180
ARGPUSH
INC
ARSLVL
LDA
ARSLVL
ASLA
ASL
A
ASLA
ASL
A
ASLA
ASL
A
CMP
OPSTKX
BCS
:APERR
TAY
DEY
LDX
*7
INC ARG STK LEVEL
ACU = ARG STACK LEVEL
TIMES 8
TEST EXCEED MAX
BR IF GT MAX
Y = NEXT ENTRY ADR
MINUS ONE
X = 7 FOR 8
:APH1 LDA VTYPE, X
STA [ARGOPSD.Y
MOVE FR0
TO ARGOPS
191
Source Code
ABCD
88
DEY
r BACKWARDS
ABCE
CA
DEX
ABCP
10F8 "ABC9
BPL :APH1
ABD1
60
RTS
; DONE
ABD2
4C2CB9
:APERR JMP ERRAOS
; STACK OVERFLOW
GETPINT — Get Positive Integer from Expression
ABD5
GETPINT
ABD5
20E0AB
JSR GETINT
; GO GET INT
ABD8
GETPI0
ABD8
A5D5
LDA FR0+1
; GET HIGH BYTE
ABDA
3001 "ABDD
BMI :GPIERR
I BR > 3 2 767
ABDC
60
RTS
; DONE
ABDD
4C32B9
:GPIERR JMP ERRLN
GEm
T — Get Integer from Expression
ABE0
20E0AA
GETINT JSR EXEXPR
; EVAL EXPR
ABE 3
GTINTO
ABE3
20P2AB
JSR ARGPOP
; POP VALUE TO FR0
ABE6
4C56AD
JMP CVFPI
1 GO CONVERT FR0 TO INT E.
RETURN
GET1INT — Get One-Byte Integer from Expression
ABE9
ABE9 20D5AB
ABEC D001 "ABEF
ABEE 60
ABEF
ABEF 203AB9
GET1INT
JSR
BNE
RTS
:ERV1
JSR
GETPINT
:ERV1
ERVAL
ARGPOP — Pop Argument Stack Entry to FRO or FR1
ABF2
ABF2 A5AA
ABF4 C6AA
ABF6
ABF6 +0A
ABF7
ABF7 +0A
ABF8
ABF8 +0A
ABF9 A8
ABFA 88
ABFB A207
ABFD BI80
ABFF 95D2
AC01 88
AC02 CA
AC03 10F8
AC05 60
ARGP2 — Pop TOS to FR1 JOS-1 to FRO
AC06 20F2AB
AC09 20B6DD
ARGP2 JSR ARGPOP
JSR MV0TO1
AC0C
4CF2AB JMP
ARGPOP
POP1
— Get a Value in FRO
- EVA
POP
AC0F
POPl
AC0F
20E0AA JSR
EXEXPR
AC12
20F2AB JSR
ARGPOP
AC15
60 RTS
GET INT <32768
IF NOT 1 BYTE, THEN ERROR
ARGPOP
LDA
ARSLVL ;
DEC
ARSLVL
ASIA
ASL
A
AS LA
ASL
A
AS LA
ASL
A
TAY
DEY
LDX
#7 ';
•APOP0 LDA
[ARGOPS],Y
STA
VTYPE.X
DEY
;
DEX
BPL
:APOP0
RTS
;
GET ARG STACK LEVEL
DEC AS LEVEL
AS LEVEL * 8
Y = START OF NEXT ENTRY
MINUS ONE
X = 7 FOR 8
; MOVE ARG ENTRY
BACKWARDS
DONE
POP TOS TO FR0
MOVE FR0 TO FR1
POP TOS TO FR0 AND RETURN
EVALUATE EXPRESSION IN STMT LINE &
POP IT INTO FR0
EVALUATE EXPRESSION
PUSH INTO FR0
192
Source Code
RTNVAR — Return V
ariable to s
/ariable Value Table fror
nFRO
AC16
RTNVAR
AC16
A5D3
LDA
VNUM
GET VAR NUMBER
AC18
2028AC
JSR
GVVTADR
AC1B
A200
LDX
#0
ACID
B5D2
:RV1
LDA VTYPE,X
MOVE FR0 TO
AC1P
919D
STA
[WWTPT], Y
VAR VALUE TABLE
AC21
C8
I NY
AC22
E8
I NX
AC23
E008
CPX
#8
AC25
90F6
"ACID
BCC
:RV1
AC27
60
RTS
DONE
GVVTADR —
Get Val
ue's Value
Table Entry Address
AC28
GVVTADR
AC28
A000
LDY
#0
CLEAR ADR HI
AC 2 A
849E
STY
WWTPT+l
AC2C
AS LA
MULT VAR NO
AC2C
+0A
ASL
A
AC2D
ASLA
BY 8
AC2D
+0A
ASL
A
AC2E
269E
ROL
WWTPT+l
AC30
ASLA
AC30
+0A
ASL
A
AC31
269E
ROL
WWTPT+l
AC33
18
CLC
THEN
AC34
6586
ADC
WTP
ADD WTP VALUE
AC36
859D
STA
WWTPT
TO FORM ENTRY
AC38
A587
LDA
WTP+1
ADR
AC 3 A
659E
ADC
WWTPT + l
AC3C
859E
STA
WWTPT+l
AC3E
60
RTS
Operator Precedence Table
AC3F
OPRTAB
AC3F
00
DB
$00
AC40
00
DB
$00
AC41
00
DB
$00
AC42
00
DB
$00
AC43
00
DB
$00
AC 44
00
DB
$00
AC45
00
DB
$00
AC46
00
DB
$00
AC47
00
DB
$00
AC48
00
DB
$00
AC49
00
DB
$00
AC 4 A
00
DB
$00
AC4B
00
DB
$00
AC4C
88
DB
$88
AC4D
88
III!
$88
AC4E
88
DB
$88
AC4F
88
DB
$88
AC 50
88
DB
$88
AC51
88
DB
$88
AC52
CC
DB
$CC
AC53
AA
DB
$AA
AC54
99
DB
$99
AC55
99
DB
$99
AC 56
AA
DB
$AA
AC57
77
DB
$77
AC58
55
DB
$55
AC59
66
DB
$66
AC 5 A
F2
DB
$F2
- ENTRIES MUST BE IN SAME ORDER AS OPNTAB
- LEFT NIBBLE IS TO GO ON STACK PREC
- RIGHT NIBBLE IS COME OFF STACK PREC
CDQ
CSOE
CCOM
CDOL
CEOS
CSC
CCR
CGTO
CGS
CTO
CSTEP
CTHEN
CPND
CLE
CNE
CGE
CGT
CLT
CEQ
CEXP
CMUL
CPLUS
CMINUS
CDIV
CNOT
COR
CAND
CLPRN
193
Source Code
AC5B
4E
AC5C
Fl
AC5D
Fl
AC5E
EE
AC5F
EE
AC60
EE
AC61
EE
AC62
EE
AC63
EE
AC64
DD
AC65
DD
AC66
P2
AC67
P2
AC68
P2
AC69
F2
AC 6 A
F2
AC6B
43
AC6C
F2
AC6D
P2
AC6E
F2
AC6F
P2
AC70
P2
AC71
F2
AC72
F2
AC73
F2
AC74
F2
AC75
F2
AC76
F2
AC77
F2
AC78
F2
AC79
F2
AC 7 A
F2
AC7B
F2
AC7C
F2
AC7D
F2
AC7E
F2
AC7F
F2
AC80
F2
AC81
F2
AC82
F2
AC83
F2
DB
?4E
DB
$F1
DB
$F1
DB
SEE
DB
$EE
DB
$EE
DB
$EE
DB
SEE
DB
SEE
DB
SDD
DB
SDD
DB
SF2
DB
SF2
DB
$F2
DB
$F2
DB
$F2
DB
$43
DB
$F2
DB
SF2
DB
$F2
DB
SF2
DB
$F2
DB
SF2
DB
$F2
DB
$F2
DB
SF2
DB
SF2
DB
$F2
DB
$F2
DB
SF2
DB
$F2
DB
$F2
DB
$F2
DB
$F2
DB
$F2
DB
$F2
DB
SF2
DB
$F2
DB
$F2
DB
SF2
DB
SF2
CRPRN
CAASN
CSASN
CSLE
CSNE
CSGE
CSLT
CSGT
CSEQ
CUPLUS
CUMINUS
CSLPRN
CALPRN
CDLPRN
CFLPRN
CDSLPR
CACOM
; FUNCTIONS
Miscellaneous Operators
Miscellaneous Operators' Executors
AC 84
XPPLUS
AC 84
2006AC
JSR
ARGP2
AC87
203BAD
JSR
FRADD
AC 8 A
4CBAAB
JMP
ARGPUSH
AC8D
XPMINUS
AC8D
2006AC
JSR
ARGP2
AC 90
2041AD
JSR
FRSUB
AC93
4CBAAB
JMP
ARGPUSH
AC96
XPMUL
AC96
2006AC
JSR
ARGP2
AC99
2047AD
JSR
FRMUL
AC9C
4CBAAB
JMP
ARGPUSH
AC9F
XPDIV
AC9F
2006AC
JSR
ARGP2
AC A 2
204DAD
JSR
FRDIV
AC A 5
4CBAAB
JMP
ARGPUSH
ACA8
XPUMINUS
AC A 8
20F2AB
JSR
ARGPOP
ACAB
A5D4
LDA
FR0
ACAD
4980
EOR
#$80
ACAF
85D4
STA
FR0
ACB1
ACB4
4CBAAB
JMP
XPUPLUS
ARGPUSH
;GET ARGUMENT INTO FR0
;GET BYTE WITH SIGN
,-FLIP SIGN BIT
; RETURN BYTE WITH SIGN CHANGED
;PUSH ON STACKS
194
Source Code
ACB4
60
RTS
ACB5
XPLE
ACB5
XPSLE
ACB5
2026AD
JSR
XCMP
ACB8
304B ~AD05
BMI
XT RUE
ACBA
F049 "AD05
BEQ
XTRUE
ACBC
1042 "AD00
BPL
XFALSE
ACBE
XPNE
ACBE
XPSNE
ACBE
2026AD
JSR
XCMP
ACC1
F03D "AD00
BEQ
XFALSE
ACC3
D040 "AD05
BNE
XTRUE
ACC5
XPLT
ACC5
XPSLT
ACC5
2026AD
JSR
XCMP
ACC8
303B "AD05
BMI
XTRUE
ACCA
1034 "AD00
BPL
XFALSE
ACCC
XPGT
ACCC
XPSGT
ACCC
2026AD
JSR
XCMP
ACCF
302F "AD00
BMI
XFALSE
ACD1
F02D ~AD00
BEQ
XFALSE
ACD3
1030 ~AD05
BPL
XTRUE
ACD5
XPGE
ACD5
XPSGE
ACD5
2026AD
JSR
XCMP
ACD8
3026 "AD00
BMI
XFALSE
AC DA
1029 "AD05
BPL
XTRUE
AC DC
XPEQ
AC DC
XPSEQ
AC DC
2026AD
JSR
XCMP
AC DP
F024 "AD05
BEQ
XTRUE
ACE1
D01D "AD00
BNE
XFALSE
ACE 3
XPAND
ACE 3
2006AC
JSR
ARGP2
ACE6
A5D4
LDA
FR0
ACE 8
25E0
AND
FR1
ACEA
F014 "AD00
BEQ
XFALSE
ACEC
D017 "AD05
BNE
XTRUE
ACEE
XPOR
ACEE
2006AC
JSR
ARGP2
ACF1
A5D4
LDA
FR0
ACF3
05E0
ORA
FR1
ACF5
F009 "AD00
BEQ
XFALSE
ACF7
D00C "AD05
BNE
XTRUE
ACF9
XPNOT
ACF9
20F2AB
JSR
ARGPOP
ACFC
A5D4
LDA
FR0
ACFE
F005 ~AD05
BEQ
XTRUE
FALL THROUGH TO
XFALSE
AD00
XFALSE
AD00
A900
LDA
#0
AD02
A8
TAY
AD03
F004 ~AD09
BEQ
XTF
AD05
XT RUE
AD05
A940
LDA
#$40
AD07
XTI
AD07
A001
LDY
#1
AD09
XTF
AD09
85D4
STA
FR0
AD0B
84D5
STY
FR0+1
AD0D
A2D6
LDX
#FR0+2
;
AD0F
A004
LDY
#FPREC-2
; 1
AD11
2048DA
JSR
ZXLY
;
AD14
85D2
STA
VTYPE
AD16
XPUSH
AD16
4CBAAB
JMP
ARGPUSH
POINT TO PART TO CLEAR
GET # OF BYTES TO CLEAR
CLEAR REST OF FR0
195
Source Code
XPSGN — Sign Function
AD19
XPSGN
AD19
20F2AB
JSR
ARGPOP
AD1C
A5D4
LDA
FR0
AD1E
F0F6 *AD16
BEQ
XPUSH
AD20
10E3 "AD05
BPL
XT RUE
AD22
A9C0
LDA
#$C0
AD24
30E1 "AD07
BMI
XT I
; GET MINUS EXPONENT
XCMP — Compare Executor
AD26
XCMP
AD26
A4A9
LDY
OPSTKX
AD28
88
DEY
AD29
B180
LDA
[ARGSTK],Y
AD2B
C92F
CMP
#CSLE
AD2D
9003 ~AD32
BCC
FRCMPP
AD2F
4C81AF
JMP
STRCMP
AD32
2006AC
FRCMPP
JSR
ARGP2
GET OPERATOR THAT
GOT US HERE
IF OP WAS ARITHMETIC
THEN DO FP REG COMP
ELSE DO STRING COMPARE
FRCMP — Compare Two Floating Point Numbers
* ON ENTRY FR0 E, FR1 CONTAIN FLOATING POINT #'S
ON EXIT CC = + FR0 > FR1
CC = - FR0 < FR1
CC = FRE0 ■ FR1
AD35
FRCMP
AD35
2041AD
JSR
FRSUB
AD38
A5D4
LDA
FR0
AD 3 A
60
RTS
SUBTRACT FR1 FROM FR0
; GET FR0 EXPONENT
; RETURN WITH CC SET
FRADD — Floating Point Add
DOES NOT RETURN IF ERROR
AD3B FRADD
AD3B 2066DA JSR
AD3E B013 "AD53 BCS
AD40 60 RTS
FADD
:ERROV
ADD TWO f
BR IF ERROR
FRSUB — Floating Point Subtract
* DOES NOT RETURN IF ERROR
AD41 FRSUB
AD41 2060DA JSR
AD44 B00D "AD53 BCS
AD46 60 RTS
FSUB
:ERROV
; SUB TWO #
; BR IF ERROR
FRMUL — Floating Point Multiply
* DOES NOT RETURN IF ERROR
AD47 FRMUL
AD47 20DBDA JSR
AD4A B007 "AD53 BCS
AD4C 60 RTS
FMUL
: ERROV
MULT TWO #
BR IF ERROR
FRDIV — Floating Point Divide
DOES NOT RETURN IF ERROR
AD4D
AD4D 2028DB
FRDIV
JSR
DIVIDE TWO #
196
Source Code
AD50
AD52
AD53
AD53
B001 "AD53
60
202AB9
BCS
RTS
ERROV
JSR
BR IF ERROR
CVFPI — Convert Floating Point to Integer
DOES NOT RETURN IP ERROR
AD56
CVFPI
AD56
20D2D9
JSR
FPI
; GO CONVERT TO INTEGER
AD59
B001 "AD5C
BCS
: ERRVAL
; IF ERROR, BR
AD5B
60
RTS
; ELSE RETURN
AD5C
ERRVAL
AD5C
203AB9
JSR
ERVAL
; VALUE ERROR
XPAASN — Arithmetic Assignment Operator
AD5F
XPAASN
AD5F
A5A9
LDA
OPSTKX
AD61
C9FF
CMP
#$FF
AD63
D00F "AD74
BNE
:AAMAT
AD65
2006AC
JSR
ARGP2
AD68
A205
LDX
#5
AD6A
B5E0
:AASN1 LDA
FR1.X
AD6C
95D4
STA
FR0,X
AD6E
CA
DEX
AD6F
10F9 "AD6A
BPL
:AASN1
AD71
4C16AC
JMP
RTNVAR
AD74
:AAMAT
AD74
A980
LDA
#?80
AD76
85B1
STA
ADFLAG
AD78
60
RTS
GET OP STACK INDEX
AT STACK START
BR IF NOT, [MAT ASSIGN]
DO SCALER ASSIGN
GO POP TOP 2 ARGS
MOVE FR1 VALUE
TO FR0
FR0 TO WT & RETURN
SET ASSIGN FLAG BIT ON
IN ASSIGN/DIM FLAG
GO POP REM OFF OPS
XPACOM — Array Comma Operator
AD79
XPACOM
AD79
E6B0
INC
COMCNT
XPRPRN - Right
Parenthesis
Operator
■
XPFLPRN -
AD7B
XPRPRN
AD7B
XPFLPRN
AD7B
A4A9
LDY
OPSTKX
AD7D
68
PLA
AD7E
68
PLA
AD7F
4C0BAB
JMP
EXOPOP
INCREMENT COMMA COUNT
FUNCTION RIGHT PAREN OPERATOR
; GET OPERATOR STACK TOP
; GO POP AND EXECUTE NEXT
OPERATOR
XPDLPRN — DIM Left Parenthesis Operator
AD82
XDPSLP
AD82
XPDLPRN
AD82
A940
LDA
#?40
AD84
85B1
STA
ADFLAG
SET DIM FLAG BIT
IN ADFLAG
FALL THRU TO XPALPRN
197
Source Code
XPALPRN — Array Left Parenthesis Operator
AD86
XPALPRN
AD86
24B1
BIT
ADFLAG
AD88
1006
"AD90
BPL
:ALP1
AD8A
A5AA
LDA
ARSLVL
AD8C
85AF
STA
ATEMP
AD8E
C6AA
DEC
ARSLVL
AD90
A900
:ALP1 LDA #0
AD92
A8
TAY
AD93
C5B0
CMP
COMCNT
AD95
F00B
"ADA2
BEQ
:ALP2
AD97
C6B0
DEC
COMCNT
AD99
20E3AB
JSR
GTINTO
AD9C
A5D5
LDA
FR0+1
AD9E
3023
"ADC3
BMI
:ALPER
ADA0
A4D4
LDY
FR0
IF NOT ASSIGN
THE BRANCH
ELSE
SAVE STACK LEVEL
OF THE VALUE ASSIGNMENT
AND PSEUDO POP IT
INIT FOR 12 =
IF COMMA COUNT =0 THEN
BR WITH 12 =
ELSE
ELSE POP 12 AND MAKE INT
ERROR IF > 32,767
ADA2 8598
ADA4 8497
:ALP2 STA INDEX2+1
STY INDEX2
;SET 12 VALUE
ADA 6
ADA9
ADAB
ADAD
ADAF
ADB1
ADC 6
ADC6
ADC8
ADCA
ADCC
ADCE
ADD0
ADD 2
ADD4
ADD6
ADD8
ADDA
ADDC
ADDE
ADE0
20E3AB
A5D4
85F5
A5D5
3012 "ADC3
85F6
ADB3 20F2AB
ADB6 24B1
ADB8 5005 "ADBF
ADBA A900
ADBC 85B1
ADBE 60
ADBF
ADBF 66D2
ADC1 B003 "ADC6
ADC3 202EB9
JSR
GTINTO
LDA
FR0
STA
ZTEMP1
LDA
FR0+1
BMI
: ALPER
STA
ZTEMP1+1
JSR
ARGPOP
BIT
ADFLAG
BVC
:ALP3
LDA
#0
STA
ADFLAG
RTS
ALP3
ROR VTYPE
BCS :ALP4
ALPER JSR ERRDIM
A5F6
C5D7
9008 "ADD4
D0F5 "ADC3
A5F5
C5D6
B0EF ~ADC3
A598
C5D9
9008
D0E7
A597
C5D8
B0E1
'ADE2
"ADC 3
ALP4
LDA
CMP
BCC
BNE
LDA
CMP
BCS
CMP
BCC
BNE
LDA
CMP
BCS
ZTEMP1+1
VTYPE+EVAD1+1
:ALP5
: ALPER
ZTEMP1
VTYPE+EVAD1
: ALPER
INDEX2+1
VTYPE+EVAD2+1
:ALP6
rALPERR
INDEX2
VTYPE+EVAD2
: ALPER
POP 12 AND MAKE INT
MOVE II
TO ZTEMP1
ERROR IF > 32,767
POP THE ARRAY ENTRY
IF NOT EXECUTING DIM
THEN CONTINUE
TURN OFF DIM BIT
IN ADFLAG
AND RETURN
IF ARRAY HAS BEEN
DIMED THEN CONTINUE
ELSE DIM ERROR
TEST INDEX 1
IN RANGE WITH
DIM1
TEST INDEX 2
IN RANGE WITH
DIM 2
ADE2
ADE5
ADE7
ADE9
ADEC
ADEF
ADF1
ADF3
ADF6
205DAF
A597
A498
2052AF
2046AF
A5D4
A4D5
2052AF
A58C
LDA
LDY
JSR
JSR
LDA
LDY
JSR
LDA
AMUL1
INDEX2
INDEX2+1
AADD
AMUL2
VTYPE+EVAADR
VTYPE+EVAADR+1
AADD
STARP
;INDEX1 a INDEX1
rINDEXl = INDEX1 + INDEX2
ZTEMP1 = ZTEMP1*6
ZTEMP1 = ZTEMP1 + DISPL
; ZTEMP1 = ZTEMP1 + ADR
198
Source Code
ADF8
A48D
ADFA
2052AF
ADFD
24B1
ADFF
1015 "
AE01
A5AF
AE03
85AA
AE05
20F2AB
AE08
A005
AE0A
B9D400
AE0D
91F5
AE0F
88
AE10
10F8 "
AE12
C8
AE13
84B1
AE15
60
AE16
A005
AE18
B1F5
AE1A
99D400
AE1D
88
AE1E
10F8 "
AE20
C8
AE21
84D2
AE23
4CBAAB
LDY
STARP+1
JSR
AADD
BIT
ADFLAG
BPL
:ALP8
LDA
ATEMP
STA
ARSLVL
JSR
ARGPOP
LDY
#5
:ALP7
LDA
FR0, Y
STA
[ZTEMP1],Y
DEY
BPL
:ALP7
I NY
STY
ADFLAG
RTS
:ALP8
LDY
#5
:ALP9
LDA
CZTEMP
STA FR0,Y
DEY
BPL :ALP9
I NY
STY
VTYPE
JMP
ARGPUSH
ZTEMP1 NOW POINTS
TO ELEMENT REQD
; IF NOT ASSIGN
; THEN CONTINUE
ELSE ASSIGN
; RESTORE ARG LEVEL
; TO VALUE AND
1 POP VALUE
MOVE VALUE
TO ELEMENT SPACE
TURN OFF
ADFLAG
DONE
MOVE ELEMENT TO
FR0
PUSH FR0 BACK TO STACK
AND RETURN
XPSLPRN — String Left Parenthesis
AE26
XPSLPRN
AE26
A5B0
LDA
COMCNT
IF NO INDEX 2
AE28
F007
"AE31
BEQ
:XSLP2
THEN BR
AE2A
2096AE
JSR
:XSPV
ELSE POP 12 AND
AE2D
8498
STY
INDEX2+1
SAVE IN INDEX 2
AE2F
8597
STA
INDEX2
AE31
2096AE
:XSLP2 JSR
:XSPV
POP INDEX 1
AE34
38
SEC
ADD DECREMENT BY ONE
AE35
E901
SBC
#1
AND PUT INTO ZTEMP1
AE37
85F5
STA
ZTEMP1
AE39
98
TYA
AE3A
E900
SBC
#0
AE3C
85F6
STA
ZTEMP1+1
AE3E
20F2AB
JSR
ARGPOP
POP ARG STRING
AE41
A5B1
LDA
ADFLAG
IF NOT A DEST STRING
AE43
100B
"AE50
BPL
:XSLP3
THEN BRANCH
AE45
05B0
ORA
COMCNT
AE47
85B1
STA
ADFLAG
AE49
A4D9
LDY
VTYPE+EVSDIM+1
INDEX 2 LIMIT
AE4B
A5D8
LDA
VTYPE+EVSDIM
IS DIM
AE4D
4C54AE
JMP
:XSLP4
AE50
A5D6
:XSLP3 LDA
VTYPE+EVSLEN
; INDEX 2 LIMIT
AE52
A4D7
LDY
VTYPE+EVSLEN+1
IS STRING LENGTH
AE54
A6B0
:XSLP4 LDX
COMCNT
IF NO INDEX 2
AE56
F010
"AE68
BEQ
:XSLP6
THEN BRANCH
AE58
C6B0
DEC
COMCNT
ELSE
AE5A
C498
CPY
INDEX2+1
AE5C
9035
~AE93
BCC
:XSLER
AE5E
D004
"AE64
BNE
:XSLP5
INDEX 2 LIMIT
AE60
C597
CMP
INDEX2
AE62
902F
"AE93
BCC
:XSLER
199
Source Code
AE64
A498
:XSLP5
LDY
INDEX2+1
•USE INDEX 2
AE66
A597
LDA
INDEX2
AS LIMIT
AE68
38
XSLP6
SEC
• LENGTH IS
AE69
E5F5
SBC
ZTEMP1
AE6B
85D6
STA
VTYPE+EVSLEN
LIMIT - INDEX 1
AE6D
AA
TAX
AE6E
98
TYA
AE6F
E5F6
SBC
ZTEMP1+1
AE71
85D7
STA
VTYPE+EVSLEN+1
AE73
901E
~AE93
BCC
: XSLER
LENGTH MUST BE
AE75
A8
TAY
GE ZERO
AE76
D003
"AE7B
BNE
:XSLP7
AE78
8A
TXA
AE79
F018
~AE93
BEQ
: XSLER
AE7B
209BAB
XSLP7
JSR
GSTRAD
GET ABS ADR
AE7E
18
CLC
AE7F
A5D4
LDA
VTYPE+EVSADR
AE81
65F5
ADC
ZTEMP1
STRING ADR
AE83
85D4
STA
VTYPE+EVSADR
STRING ADR + INDEX 1
AE85
A5D5
LDA
VTYPE+EVSADR+1
AE87
65F6
ADC
ZTEMP1+1
AE89
85D5
STA
VTYPE+EVSADR+1
AE8B
24B1
BIT
ADFLAG
IF NOT ASSIGN
AE8D
1001
~AE90
BPL
:XSLP8
THEN BR
AE8F
60
RTS
ELSE RETURN TO ASSIGN
AE90
4CBAAB
XSLP8
JMP
ARGPUSH
PUSH ARG AND RETURN
AE93
2036B9
XSLER
JSR
ERRSSL
XSPV
— Pop
Index Va
lue as Intege
r and Insure Not Zero
AE96
XSPV
AE96
20E3AB
JSR
GTINTO
GO GET THE INTEGER
AE99
A5D4
LDA
FR0
GET VALUE LOW
AE9B
A4D5
LDY
FR0+1
GET VALUE HI
AE9D
D003
"AEA2
XSPV1
BNE
: XSPVR
RTN IF VH NOT ZERO
AE9F
AA
TAX
TEST VL
AEA0
F0F1
"AE93
BEQ
: XSLER
BR VL.VH =
AEA2
60
XSPVR
RTS
DONE
XSAASN — String Assign Operator
AEA3
XSAASN
AEA3
2098AB
JSR
AAPSTR
; POP STR WITH ABS ADR
AEA6
RISASN
AEA6
A5D4
LDA
VTYPE+EVSADR
; MVFA = ADR
AEA8
8599
STA
MVFA
AEAA
A5D5
LDA
VTYPE+EVSADR+1
AEAC
859A
STA
MVFA+1
AEAE
A5D6
LDA
VTYPE+EVSLEN
AEB0
85A2
STA
MVLNG
; MVLNG = LENGTH
AEB2
A4D7
LDY
VTYPE+EVSLEN+1
AEB4
84A3
STY
MVLNG+1
AEB6
A4A9
LDY
OPSTKX
. IF AT T op OF
AEB8
C0FF
CPY
#SFF
; OP STACK
AEBA
F00F "AECB
BEQ
:XSA1
; THEN BR
ELSE
AEBC
A980
LDA
#S80
; SET ASSIGN BIT
AEBE
85B1
STA
ADFLAG
; IN ASSIGN/DIM FLAG
AEC0
200BAB
JSR
EXOPOP
; AND PROCESS SUBSTRING
AEC3
A5D7
LDA
VTYPE+EVSLEN+1
; A,Y =
AEC5
A4D6
LDY
VTYPE+EVSLEN
; DEST LEN
AEC7
26B1
ROL
ADFLAG
; TURN OFF ASSIGN
AEC9
B007 "AED2
BCS
:XSA2A
; AND BR
200
Source Code
AECB
2098AB
AECE
A5D9
AED0
A4D8
AED2
AED2
C5A3
AED4
9006 "AEDC
AED6
D008 "AEE0
AED8
C4A2
AEDA
B004 "AEE0
AEDC
85A3
AEDE
84 A 2
AEE0
18
AEE1
A5D4
AEE3
65A2
AEE5
A8
AEE6
A5D5
AEE8
65A3
AEEA
AA
AEEB
38
AEEC
98
AEED
E58C
AEEP
85F9
AEF1
8A
AEF2
E58D
AEF4
85FA
AEF6
38
AEF7
A900
AEF9
E5A2
AEFB
85A2
AEFD
38
AEFE
A599
AF00
E5A2
AF02
8599
AF04
A59A
AF06
E900
AF08
859A
AF0A
38
AF0B
A5D4
AF0D
E5A2
AF0F
859B
AF11
A5D5
AF13
E900
AF15
859C
POP STR WITH ABS ADR
LDY
VTYPE+EVSDIM+1
VTYPE+EVSDIM
A,Y = DEST LENGTH
:XSA2A
CMP MVLNG+1
BCC :XSA3
BNE :XSA4
CPY MVLNG
BCS :XSA4
:XSA3 STA MVLNG+1
STY MVLNG
AF17 2047A9
AF1A
A5D3
AF1C
2089AB
AF1F
38
AF20
A5F9
AF22
E5D4
AF24
A8
AF25
A5FA
AF27
E5D5
AF29
AA
:XSA4
CLC
AF2A A902
AF2C 25B1
AF2E F00F "AF3F
AF30 A900
LDA
VTYPE+EVSADR ;
ADC
MVLNG ;
TAY
LDA
VTYPE+EVSADR+1
ADC
MVLNG+1
TAX
SEC
TYA
SBC
STARP ;
STA
ZTEMP3 ;
TXA
SBC
STARP+1 ;
STA
ZTEMP3+1
SEC
LDA
#0 ;
SBC
MVLNG ;
STA
MVLNG ;
SEC
LDA
MVFA
SBC
MVLNG ;
STA
MVFA ;
LDA
MVFA+1
SBC
#0
STA
MVFA+1
SEC
LDA
VTYPE+EVSADR
SBC
MVLNG ;
STA
MVTA
LDA
VTYPE+EVSADR+1 ;
SBC
#0 ;
STA
MVTA+1
JSR
FMOVER ;<
LDA
VNUM ;
JSR
GETVAR ;
SEC
.
LDA
ZTEMP3 ;
SBC
VTYPE+EVSADR
TAY
LDA
ZTEMP3+1
SBC
VTYPE+EVSADR+1
TAX
LDA
#02
AND
ADFLAG ;
BEQ
: XSA5
LDA
#0 ;
IF DEST LENGTH
LESS THAN MOVE LENGTH
SET MOVE LENGTH
= DIST LENGTH
MOVE LENGTH PLUS
START ADR IS
END ADR
END ADR MINUS
START OF STRING
SPACE IS DISPL
TO END OF STRING
WHICH WE SAVE
IN ZTEMP3
SET MOVE LENGTH LOW
= $100 - MVL [L]
BECAUSE OF THE WAY
FMOVE WORKS
ADJUST MVFA TO
CONFORM WITH MVL
CHANGE
MOVE THE DEST
STRING ADR TO
MVTA AND
MAKE IT CONFORM
WITH MVL
GO DO THE VERY FAST MOVE
GO GET ORIGNAL DEST
STRING
DISPL TO END OF
MOVE MINUS DISPL
TO START OF STRING
IS OUR RESULT LENGTH
IF THE DESTINATION
LENGTH WAS IMPLICT
SET NEW LENGTH
CLEAR
201
Source Code
AF32 85B1
AF34
E4D7
AF36
9006
~AF3E
AF38
D005
"AF3F
AF3A
C4D6
AF3C
B001
"AF3F
AF3E
60
AF3F
84D6
AF41
86D7
AF43
4C16AC
STA
ADFLAG
; FLAG
ELSE FOR EXPLICT LENGTH
CPX
VTYPE+EVSLEN+1
; IF NEW LENGTH
BCC
:XSA6
; GREATER THAN
BNE
:XSA5
; OLD LENGTH THEN
CPY
VTYPE+EVSLEN
; SET NEW LENGTH
BCS
:XSA5
; ELSE DO NOTHING
:XSA6
RTS
:XSA5 STY VTYPE+EVSLEN
STX VTYPE+EVSLEN+1
JMP RTNVAR
AMUL2 — Integer Multiplication of ZTEMP1 by 6
AF46
AMUL2
AF46
06F5
ASL
ZTEMP1
• ZTEMP1 = ZTEMP1*2
AF48
26F6
ROL
ZTEMP1+1
AF4A
A4F6
LDY
ZTEMP1+1
; SAVE ZTEMP1*2 IN [A,Y]
AF4C
A5F5
LDA
ZTEMP1
AF4E
06F5
ASL
ZTEMP1
; ZTEMP1 = ZTEMP1*4
AF50
26F6
ROL
ZTEMP1+1
AADD
— Integer Addition of [A,Y] to ZTEMP1
AF52
AADD
AF52
18
CLC
AF53
65F5
ADC
ADC
ZTEMP1
; ADD LOW ORDER
AF55
85F5
STA
ZTEMP1
AF57
98
TYA
AF58
65F6
ADC
ZTEMP1+1
; ADD HIGH ORDER
AF5A
85F6
STA
ZTEMP1+1
AF5C
60
RTS
; DONE
AMUl
— Integer Multiplication of ZTEMP1 by DIM2
AF5D
AHUL1
AF5D
A900
LDA
#0
■ CLEAR PARTIAL PRODUCT
AF5F
85F7
STA
ZTEMP4
AF61
85F8
STA
ZTEMP4+1
AF63
A010
LDY
#510
■ SET FOR 16 BITS
AF65
A5F5
:AM1
LDA
ZTEMP1
• GET MULTIPLICAN
AF67
LSRA
■ TEST MSB = ON
AF67
+4A
LSR
A
AF68
900C
"AF76
BCC
:AM3
- BR IF OFF
AF6A
18
CLC
AF6B
A2FE
LDX
#$FE
; ADD MULTIPLIER
AF6D
B5F9
:AM2
LDA
ZTEMP4+2.X
; TO PARTIAL PRODUCT
AF6F
75DA
ADC
VTYPE+EVAD2+2.X
AF71
95F9
STA
ZTEMP4+2.X
AF73
E8
I NX
AF74
D0F7
"AF6D
BNE
:AM2
AF76
A203
:AM3
LDX
#3
| MULT PRODUCT BY 2
AF78
76F5
:AM4
ROR
ZTEMP1.X
AF7A
CA
DEX
AF7B
10FB
"AF78
BPL
:AM4
AF7D
88
DEY
; TEST MORE BITS
AF7E
D0E5
~AF65
BNE
:AM1
,- BR IF MORE
STRCMP — String Compare
AF81
STRCMP
AF81
2098AB
JSR
AAPSTR
AF84
20B6DD
JSR
MV0TO1
AF87
2098AB
JSR
AAPSTR
POP STRING WITH ABS ADR
MOVE B TO FR1
POP STRING WITH ABS ADR
202
Source Code
AF8A
AF8C
AF8P
AF90
AF92
AF95
AF97
AF98
A2D6
20BCAP
08
A2E2
20BCAF
F013 "AFAA
28
F00D "AFA7
IFR0-2+EVSLEN
JSR
PHP
LDX
JSR
BEQ
PLP
BEQ
ZPADEC
#FRl-2+EVSLEN
ZPADEC
:SC2
:SCLT
GO DEC STR A LEN
SAVE RTN CODE
GO DEC STR B LEN
BR STR B LEN =
GET STR A COND CODE
BR STR A LEN =
AF9A A000 LDY #0 ;
AF9C B1D4 LDA [FR0-2+EVSADR] , Y
AF9E D1E0 CMP [FR1-2+EVSADR] , Y
AFA0 F00C ~AFAE BEQ :SC3 ;
AFA2 9003 "AFA7 BCC :SCLT ;
COMPARE A BYTE
; OF STRING A
; TO STRING B
BR IF SAME
BR IF A<B
AFA4 A901
AFA6 60
:SCGT LDA
RTS
SI
A>B
AFA7 A980
AFA9 60
:SCLT LDA
RTS
#$80
AFAA 28
AFAB
AFAD
AFAE
AFB0
AFB2
AFB4
AFB6
AFB8
AFBA
D0F7 "AFA4
60
E6D4
D002 ~AFB4
E6D5
E6E0
D0D2 ~AF8A
E6E1
D0CE "AF8A
:SC2
BNE
:SCEQ
:SC3
BNE
INC
:SC4
BNE
INC
BNE
RTS
INC
:SCGT
FR0-2+EVSADR
:SC4
FR0-1+EVSADR
FR1-2+EVSADR
!SC1
FR1-1+EVSADR
:SC1
ZPADEC — Decrement a Zero-Page Double Word
AFBC
AFBC
AFBE
AFC0
AFC 2
AFC 4
AFC 6
AFC8
AFC 9
B500
D006
B501
F005
D601
D600
A8
60
'AFC 9
ZPADEC
LDA
BNE
LDA
BEQ
DEC
:ZPAD1 DEC
TAY
:ZPADR RTS
0,X
:ZPAD1
1,X
:ZPADR
1,X
0,X
IF STR A LEN NOT
ZERO THEN A>B
ELSE A=B
; INC STR A ADR
INC STR B ADR
GET LOW BYTE
BR NOT ZERO
GET HI BYTE
BR IF ZERO
DEC HIGH BYTE
DEC LOW BYTE
SET NE COND CODE
RETURN
Functions
XPLEN — Length Function
AFCA
XPLEN
AFCA
2098AB
JSR
AAPSTR
POP STRING WITH ABS ADR
AFCD
A5D6
LDA
VTYPE+EVSLEN
MOVE LENGTH
AFCF
A4D7
LDY
VTYPE+EVSLEN+1
AFD1
XPIFP
AFD1
85D4
STA
FR0
TO TOP OF FR0
AFD3
84D5
STY
FR0+1
AFD5
20AAD9
XPIFP1 JSR
CVIFP
AND CONVERT TO FP
AFD8
XPIFP2
AFD8
A900
LDA
#0
CLEAR
AFDA
85D2
STA
VTYPE
TYPE AND
AFDC
85D3
STA
VNUM
NUMBER
AFDE
4CBAAB
JMP
ARGPUSH
PUSH TO STACK AND RETURN
XPPEI
K — PEEK Function
AFEl
XPPEEK
AFE1
20E3AB
JSR
GTINTO
• GET INT ARG
AFE4
A000
LDY
#0
AFE6
B1D4
LDA
[FR0],Y
• GET MEM BYTE
AFE8
4CD1AF
JMP
XPIFP
• GO PUSH AS FP
203
Source Code
XPFRE — FRE Function
AFEB
XPFRE
AFEB
20F2AB
JSR
ARGPOP
; POP DUMMY ARG
AFEE
38
SEC
AFEF
ADE502
LDA
HIMEM
; NO FREE BYTES
AFF2
E590
SBC
MEMTOP
; = HIMEM-MEMTOP
AFF4
85D4
STA
FR0
AFF6
ADE602
LDA
HIMEM+1
AFF9
E591
SBC
MEMTOP+1
AFFB
85D5
STA
FR0+1
AFFD
4CD5AF
JMP
XPIFP1
; GO PUSH AS FP
XPVAL — VAL Function
B000
XPVAL
B000
2079BD
JSR
SETSEOL ;
B003
A900
LDA
#0 ;
B005
85F2
STA
CIX ;
B007
2000D8
JSR
CVAFP f
Restore Character
B00A
2099BD
JSR
RSTSEOL ;
B00D
90C9 "AFD8
BCC
XPIFP2
B00F
':VERR
B00F
201CB9
JSR
ERSVAL
XPASC — ASC Function
B012
XPASC
B012
2098AB
JSR
AAPSTR
Get 1>T Byte of String
B015 A000
B017 B1D4
B019 4CD1AF
LDY
LDA
PUT EOL AT STR END
GET NUMERIC TERMINATOR
SET INDEX INTO BUFFER =
CONVERT TO F.P.
RESET END OF STR
GET STRING ELEMENT
#0 ; GET INDEX TO 1ST BYTE
[FR0-2+EVSADR],Y ; GET BYTE
B01C
XPADR
B01C
2098AB
JSR
AAPSTR
;GET STRING
B01F
4CD5AF
JMP
XPIFP1
| FINISH
XPPDL — Function Paddle
B022 XPPDL
B022 A900 LDA
B024 F00A ~B030 BEQ
XPSTICK — Function Joystick
B026
B026 A908
B028 D006
XPSTICK
LDA
BNE
#0
:GRF
#8
:GRF
XPPTRIG — Function Paddle Trigger
B02A XPPTRIG
B02A A90C LDA #$0C
B02C D002 "B030 BNE :GRF
XPSTRIG — Function Joystick Trigger
#514
B02E
B02E A914
XPSTRIG
LDA
GET DISPL FROM BASE ADDR
; GET DISP FROM BASE ADDR
; GET DISPL FROM BASE ADDR
GET DISP FROM BASE ADDR
204
Source Code
B030
:GRP
B030
48
PHA
B031
20E3AB
JSR
GTINTO
B034
A5D5
LDA
PR0+1
B036
D00E "B046
BNE
:ERGRP
B038
A5D4
LDA
FR0
B03A
68
PLA
B03B
18
CLC
B03C
65D4
ADC
FR0
B03E
AA
TAX
B03F
BD7002
LDA
GRFBAS.X
B042
A000
LDY
#0
B044
F08B "AFD1
BEQ
XPIFP
B046
B046 203AB9
ERGRF
JSR
GET INTEGER FROM STACK
HIGH ORDER BYTE
SHOULD BE =0
GET #
GET DISPL FROM BASE
ADD MORE DISPL
GET VALUE
GO CONVERT & PUSH ON STACK
ERVAL
XPSTR — STR Function
B049 XPSTR
B049 20F2AB JSR
B04C 20E6D8 JSR
Build String Element
B04F A5F3 LDA
B051 85D4 STA
B053 ASF4 LDA
B055 85D5 STA
Get Length
B057 A0FF
B059
B059 C8
B05A B1F3
B05C
B05E
B060
B062
10FB
297F
91F3
C8
LDY
:XSTR1
INY
LDA
"B059 BPL
AND
STA
INY
B063 84D6
STY
ARGPOP
CVFASC
INBUFF
FR0-2+EVSADR
INBUFF+1
FR0-1+EVSADR
B065 D017 B07E
#SFF
[INBUFF], Y
:XSTR1
#?7F
ClNBUFF], Y
FR0-2+EVSLEN
:CHR
GET VALUE IN FR0
CONVERT TO ASCII
INIT FOR LENGTH COUNTER
BUMP COUNT
GET CHAR
IS MSB NOT ON, REPEAT
TURN OFF MSB
RETURNS CHAR TO BUFFER
INC TO GET LENGTH
SET LENGTH LOW
JOIN CHR FUNCTION
XPCHR-CHR Function
B067
B067
20F2AB
B06A
B06D
B06F
2056AD
A5D4
8DC005
Build
String Eli
B072
B074
B076
B078
A905
85D5
A9C0
8SD4
B07A
B07C
A901
85D6
B07E
B080
A900
85D7
XPCHR
JSR
JSR
LDA
STA
LDA
STA
LDA
STA
LDA
STA
LDA
STA
ARGPOP
CVFPI
FR0
LBUFF+$40
GET VALUE IN FR0
CONVERT TO INTEGER
GET INTEGER LOW
SAVE
#(LBUFF+$40)/256 ; SET ADDR
FR0-1+EVSADR ; X
#(LBUFF+$40)S,255 ; X
FR0-2+EVSADR ; X
#1
FR0-2+EVSLEN
#0
FR0-I+EVSLEN
SET LENGTH LOW
SET LENGTH HIGH
X
205
Source Code
B082 85D3
B084 A983
B086 85D2
STA VNUM r CLEAR VARIABLE #
LDA #EVSTR+EVSDTA+EVDIM ; GET TYPE FLAGS
STA VTYPE ; SET VARIABLE TYPE
B088 4CBAAB
JMP
XPRND — RND Function
B08B
B08B
A2A8
B08D
A0B0
B08P
2098DD
B092
20F2AB
B095
AC0AD2
B098
84D4
B09A
AC0AD2
B09D
84D5
B09F
20AAD9
B0A2
204DAD
B0A5
4CBAAB
B0A8
4206553600
00
XPRND
LDX
LDY
JSR
JSR
LDY
STY
LDY
STY
JSR
JSR
JMP
RNDDIV DB
ARGPUSH
IRNDDIVS.255
#RNDDIV/256
FLD1R
ARGPOP
RNDLOC
FR0
RNDLOC
FR0+1
CVIFP
FRDIV
B0AE
B0AE
B0B1
B0B3
B0B5
B0B7
20F2AB
A5D4
297F
85D4
4CBAAB
XPABS
JSR
LDA
AND
STA
JMP
XPABS — Absolute Value Function
XPUSR — USR Function
B0BA
B0BA 20C3B0
B0BD 20AAD9
B0C0 4CBAAB
B0C3
B0C3 A5B0
B0C5 85C6
B0C7
B0C7 20E3AB
B0CA C6C6
B0CC 3009 "B0D7
B0CE A5D4
B0D0 48
A5D5
48
4CC7B0
B0D1
B0D3
B0D4
B0D7
B0D7 A5B0
B0D9 48
B0DA 6CD400
XPUSR
JSR
JSR
JMP
LDA
STA
:USR1
JSR
DEC
BMI
LDA
PHA
LDA
PHA
JMP
:USR2
LDA
PHA
JMP
XPINT — Integer Function
B0DD
B0DD 20F2AB
B0E0 20E6B0
B0E3 4CBAAB
XPINT
JSR
JSR
JMP
PUSH ON STACK
POINT TO 65535
X
MOVE IT TO FR1
CLEAR DUMMY ARG
GET 2 BYTE RANDOM #
X
X
X
CONVERT TO INTEGER
DO DIVIDE
PUT ON STACK
$42, $06, 555, $36,0,0
ARGPOP
FR0
#$7F
FR0
ARGPUSH
:USR
CVIFP
ARGPUSH
COMCNT
2TEMP2
GTINTO
ZTEMP2
:USR2
FR0
FR0+1
:USR1
COMCNT
[FR0]
ARGPOP
XINT
ARGPUSH
GET ARGUMENT
GET BYTE WITH SIGN
AND OUT SIGN
SAVE
PUSH ON STACK
PUT RETURN ADDR IN CPU STACK
CONVERT FR0 TO FP
PUSH ON STACK
;GET COMMA COUNT
;SET AS # OF ARG FOR LOOP
CONTROL
; GET AN INTEGER FROM OP STACK
,-DECR # OF ARGUMENTS
;IF DONE THEM ALL, BRANCH
GET ARGUMENT LOW
PUSH ON STACK
GET ARGUMENT HIGH
PUSH ON STACK
GET NEXT ARGUMENT
GET f OF ARGUMENTS
PUSH ON CPU STACK
GO TO USER ROUTINE
GET NUMBER
GET INTEGER
PUSH ON ARGUMENT STACK
206
Source Code
XINT — Take Integer Part of FRO
B0E6
XINT
B0E6
A5D4
LDA
FR0
B0E8
297F
AND
#$7F
B0EA
38
SEC
B0EB
E93F
SBC
#$3F
B0ED
1002
"B0F1
BPL
:XINT1 ;
B0EF
A900
LDA
#0 ;
B0F1
:XINT1
B0F1
AA
TAX
B0F2
A900
LDA
*0 ;
B0F4
A8
TAY
B0F5
:INT2
B0F5
E005
CPX
IFMPREC ;
B0F7
B007
"B100
BCS
:XINT3 ;
B0F9
15D5
ORA
FR0M,X ;
B0FB
94D5
STY
FR0M,X ;
B0FD
E8
I NX
B0FE
D0F5
"B0F5
BNE
:INT2
B100
:X1NT3
B100
A6D4
LDX
FR0 ;
B102
1014
"B118
BPL
:XINT4 f
B104
AA
TAX
>
B105
F011
"B118
BEQ
:XINT4 ;
GET EXPONENT
AND OUT SIGN BIT
GET LOCATION OF 1ST FRACTION
BYTE
IF > OR = 0, THEN BRANCH
ELSE SET =0
PUT IN X AS INDEX INTO FR0
SET ACCUM TO ZERO FOR ORING
ZERO Y
IS D.P. LOC > OF = 57
IF YES, LOOP DONE
OR IN THE BYTE
ZERO BYTE
POINT TO NEXT BYTE
UNCONDITIONAL BRANCH
GET EXPONENT
BR IF # IS PLUS
GET TOTAL OF ORED BYTES S,
SET CC
IF ALL BYTES WERE ZERO
BRANCH
# IS NEGATIVE AND NOT A WHOLE # CADD -1]
B107
A2E0
LDX
#FR1
B109
2046DA
JSR
ZF1
B10C
A9C0
LDA
#$C0
B10E
85E0
STA
FR1
B110
A901
LDA
#1
B112
85E1
STA
FR1+1
B114
203BAD
JSR
FRADD
B117
60
RTS
B118
:XINT4
B118
4C00DC
JMP
NORM
ZERO
FI
a
PUT
-1
IN
FRl
X
X
X
ADD
IT
; GO NORMALIZE
Transcendental Functions
XPSIN — Sine Function
BUB
XPSIN
B11B
20F2AB
JSR
ARGPOP
B11E
20A7BD
JSR
SIN
B121
B03F "B162
BCS
:TBAD
B123
903A ~B15F
BCC
:TGOOD
XPCOS — Cosine Function
B125
XPCOS
B125
20F2AB
JSR
ARGPOP
B128
20B1BD
JSR
COS
B12B
B035 "B162
BCS
:TBAD
B12D
9030 "B15F
BCC
:TGOOD
XPATN — Arc Tangent Function
B12F
XPATN
B12F
20F2AB
JSR
ARGPOP
B132
2077BE
JSR
ATAN
B135
B02B "B162
BCS
:TBAD
B137
9026 "B15F
BCC
:TGOOD
;GET ARGUMENT
;GET ARGUMENT
207
Source Code
XPLOG — LOG Function
B139
XPLOG
B139
20F2AB
JSR
ARGPOP
B13C
20CDDE
JSR
LOG
B13F
B021 "B162
BCS
:TBAD
B141
901C "B15F
BCC
:TGOOD
XP4-1C
— LOG Base 10
B143
XPL10
B143
20F2AB
JSR
ARGPOP
B146
20D1DE
JSR
LOG 10
B149
B017 ~B162
BCS
:TBAD
B14B
9012 "B15F
BCC
:TGOOD
XPEXI
» — EXP Function
B14D
XPEXP
B14D
20F2AB
JSR
ARGPOP
B150
20C0DD
JSR
EXP
B153
B00D "B162
BCS
:TBAD
B155
9008 "B15F
BCC
:TGOOD
XPSQR — Square Root Function
B157 XPSQR
B157 20F2AB JSR
B15A 20E5BE JSR
B15D B003 "B162 BCS
ARGPOP
SQR
:TBAD
FALL THREE TO :TGOOD
B15F
B15F
4CBAAB
B162
B162
203AB9
XPPOWER-
Expo
B165
B165
2006AC
B168
A5D4
B16A
D00B
~B177
B16C
A5E0
B16E
F004
"B174
B170
10ED
"B15F
B172
30EE
"B162
B174
B174
4C05AD
B177
B177
1030
"B1A9
B179
297F
B17B
85D4
B17D
A5E0
B17F
297F
B181
38
B182
E940
B184
30DC
"B162
B186
A206
B188
C905
B18A
9004
"B190
B18C
A001
B18E
D008
"B198
B190
:TGOOD
JMP
B190 85F5
:TBAD
JSR
ERVAL
;ntij
1 Operator [A* *B]
XPPOWER
JSR
ARGP2
LDA
FR0
BNE
:N0
LDA
FR1
BEQ
:P0
BPL
:TGOOD
BM1
:TBAD
:P0
JMP
XTRUE
:N0
BPL
:SPEVEN
AND
#$7F
STA
FR0
LDA
FR1
AND
#$7F
SEC
SBC
#?40
BMI
:TBAD
LDX
#6
'
CMP
#5
BCC
:SP4
LDY
#1
BNE
:SP3
:SP4
'
STA
ZTEMP1
;PUSH ARGUMENT ON STACK
;GET ARGUMENT IN FR0,FR1
;IS BASE = ?
;IF BASE NOT 0, BRANCH
;TEST EXPONENT
rIF =
;IF >0,
; BRANCH
ANSWER =
VALUE ERROR
;IF =0, ANSWER
IF BASE + THEN NO SPECIAL
PROCESS
AND OUT SIGN BIT
SET AS BASE EXPONENT
GET EXPONENT OF POWER
AND OUT SIGN BIT
IS POWER <1?
IF YES, ERROR
GET INDEX TO LAST DIGIT
IF # CAN HAVE DECIMAL
PORTION, THEN BR
SAVE EXP -40
208
Source Code
B192
38
SEC
B193
A905
LDA
#5
B195
E5F5
SBC
ZTEMP1
B197
A8
TAY
B198
:SP3
B198
CA
DEX
B199
88
DEY
B19A
F006
"B1A2
BEQ
:SP2
B19C
B5E0
LDA
FR1,X
B19E
D0C2
"B162
BNE
:TBAD
B1A0
F0F6
"B198
BEQ
:SP3
B1A2
:SP2
B1A2
A080
LDY
#$80
B1A4
B5E0
LDA
FR1.X
B1A6
LSRA
B1A6
+4A
LSR
A
B1A7
B002
"B1AB
BCS
:POWR
B1A9
:SPEVEN
B1A9
A000
LDY
#0
B1AB
:POWR
B1AB
9G
TYA
B1AC
48
PHA
Save Exponent [from
FR1]
B1AD
A205
LDX
#FMPREC
B1AF
:P0WR1
B1AF
B5E0
LDA
FR1.X
B1B1
48
PHA
B1B2
CA
DEX
B1B3
10FA
"B1AF
BPL
:P0WR1
B1B5
20D1DE
JSR
LOG 10
B1B8
B0A8
"B162
BCS
:TBAD
Pull Exponent into FR1 [from CPU Stack]
B1BA
B1BC
B1BE
B1BE
B1BF
B1C1
B1C2
B1C3
A200
A005
68
95E0
E8
88
10F9 "B1BE
LDX
LDY
: P0WR2
PLA
STA
INX
DEY
BPL
#0
#FMPREC
;DEC COUNTER
:P0WR2
;GET # BYTES POSSIBLE
; GET # BYTES THAT COULD BE
DECIMAL
; SET COUNTER
DEC COUNTER
IF DONE GO TEST EVEN/ODD
GET BYTE OF EXPONENT
IF NOT =0, THEN VALUE ERROR
REPEAT
,- GET ODD FLAG
;GET BYTE OF EXPONENT
; IS IT ODD[LAST BIT OFF]?
; IF YES, BR
;GET POINTER INTO FR1
; GET A BYTE
,-PUSH ON CPU STACK
.-POINT TO NEXT BYTE
;BR IF MORE TO DO
;TAKE LOG OF BASE
;GET POINTER INTO FR1
;SET COUNTER
j PUT IN FR1
;INCR POINTER
;BR IF MORE TO DO
B1C5 2047AD JSR FRMUL
B1C8 20CCDD JSR EXP10
B1CB B009 "B1D6 BCS :EROV
;GET LOG OF NUMBER
;GET NUMBER
B1CD
BICE
68
108F
'B15F
PLA
BPL
:TGOOD
GET EVEN/ODD FLAG
IF EVEN, GO PUT ON STACK
B1D0 05D4 ORA FR0
B1D2 85D4 STA FR0
B1D4 D089 "B15F BNE :TGOOD
IF ODD MAKE ANSWER-
X
PUSH ON STACK
B1D6
B1D6
:EROV
JSR
209
Source Code
Statements
XDIM & XCOM - Execute DIM and COMMON Statements
B1D9
XDIM
B1D9
XCOM
B1D9
A4A8
:DC1
LDY
STINDEX
• IF NOT AT
B1DB
C4A7
CPY
NXTSTD
■ STATEMENT END
B1DD
9001 "
B1E0
BCC
:DC2
■ THEN CONTINUE
B1DP
60
RTS
■ RETURN
B1E0
20E0AA
:DC2
JSR
EXEXPR
■ GO SET UP VIA EXECUTE E)
B1E3
A5D2
LDA
VTYPE
; GET VAR TYPE
B1E5
RORfl
• SHIFT DIM BIT TO CARRY
B1E5
+6A
ROR
A
B1E6
9003 "
B1EB
BCC
:DC3
- CONTINUE IF NOT YET DIM1
B1E8
202EB9
:DCERR
JSR
ERRDIM
■ ELSE ERROR
B1EB
38
•DC3
SEC
• TURN ON
B1EC
ROLA
■ DIM FLAG
B1EC
+2A
ROL
A
B1ED
85D2
STA
VTYPE
- AND RESET
B1EF
302F "
B220
BMI
:DCSTR
• AND BR IF STRING
B1F1
A4F5
LDY
ZTEMP1
; INC 11 BY 1
B1F3
A6F6
LDX
ZTEMP1+1
; AND SET AS DIM1
B1F5
C8
I NY
B1F6
D003 *
B1FB
BNE
:DC4
B1F8
E8
INX
B1F9
30ED "
B1E8
BMI
: DCERR
; BR IF OUT OF BOUNDS
B1FB
84D6
:DC4
STY
VTYPE+EVAD1
B1FD
86D7
STX
VTYPE+EVAD1+1
BIFF
84F5
STY
ZTEMP1
; ALSO PUT BACK ONTO
B201
86F6
STX
ZTEMP1+1
; INDEX 1 FOR MULT
B203
A497
LDY
INDEX2
- INC INDEX 2 BY 1
B205
A698
LDX
INDEX2+1
; AND SET AS DIM 2
B207
C8
INY
B208
D003 "
B20D
BNE
:DC5
B20A
E8
INX
B20B
30DB *
B1E8
BMI
: DCERR
; BR IF OUT OF BOUNDS
B20D
84D8
:DC5
STY
VTYPE+EVAD2
B20F
86D9
STX
VTYPE+EVAD2+1
B211
205DAF
JSR
AMUL1
: ZTEMP1 = ZTEMP1*D2
B214
2046AF
JSR
AMUL2
; ZTEMP1 = ZTEMP1*6
RESULT IS AN ARRAY
SPACE REQD
B217
A4F5
LDY
ZTEMP1
; A,Y = LENGTH
B219
A5F6
LDA
ZTEMP1+1
B21B
30CB *
B1E8
BMI
: DCERR
B21D
4C34B2
JMP
: DCEXP
; GO EXPAND
B220
:DCSTR
B220
A900
LDA
#0
; SET CURRENT LENGTH =0
B222
85D6
STA
EVSLEN+VTYPE
B224
85D7
STA
EVSLEN+1+VTYPE
B226
A4F5
LDY
ZTEMP1
; MOVE INDEX
B228
84D8
STY
VTYPE+EVSDIM
; TO STR DIM
B22A
A5F6
LDA
ZTEMP1+1
; [ALSO LOAD A,Y]
B22C
85D9
STA
VTYPE+EVSDIM+1
,- FOR EXPAND
B22E
D004 *
B234
BNE
: DCEXP
,- INSURE DIM
B230
C000
CPY
#0
; NOT ZERO
B232
F0B4 "
B1E8
BEQ
: DCERR
; FOR STRING
B234
:DCEXP
B234
A28E
LDX
#ENDSTAR
,• POINT TO END ST 5, ARRAY
SPACE
B236
2081A6
JSR
EXPAND
I GO EXPAND
210
Source Code
B239
38
B23A
A597
B23C
E58C
B23E
85D4
B240
A598
B242
E58D
B244
85D5
B246
2016AC
B249
4CD9B1
SEC
LDA
SBC
STA
LDA
SBC
STA
JSR
JMP
SVESA
STARP
VTYPE+EVSADR
SVESA+1
STARP+1
VTYPE+EVSADR+1
RTNVAR
:DC1
CALCULATE DISPL INTO
ST/ARRAY SPACE
AND PUT INTO VALUE BOX
RETURN TO VAR VALUE TABLE
AND GO FOR NEXT ONE
XPOKE — Execute POKE
B24C
B24C
B24F
B251
B253
B255
20E0AB
A5D4
8595
A5D5
8596
XPOKE
JSR
LDA
STA
LDA
STA
GETINT
FR0
POKADR
FR0+1
POKADR+1
GET INTEGER ADDR
SAVE POKE ADDR
B257 20E9AB
JSR
GET 1 INT
GET 1 BYTE INTEGER TO POKE
B25A A5D4 LDA
B25C A000 LDY
B25E 9195 STA
B260 60 RTS
XDEG — Execute DEG
B261 XDEG
B261 A906 LDA
B263 85FB STA
B265 60 RTS
FR0
#0
[POKADR], Y
#DEGON
RADFLG
; GET INTEGER TO POKE
; GET INDEX
;GET INDEX
GET DEGREES FLAG
SET FOR TRANSCENDENTALS
XRAD — Execute RAD
B266 XRAD
B266 A900 LDA
B268 85FB STA
B26A 60 RTS
# RADON
RADFLG
XREST — Execute RESTORE Statement
B26B
B26B A900
B26D 85B6
XREST
LDA
STA
#0
DATAD
GET RADIAN FLAG
SET FOR TRANSCENDENTALS
ZERO DATA DISPL
B26F
B272
B274
B275
2010B9
9003 "B277
A8
F007 "B27E
B277 20D5AB
B27A A5D5
B27C A4D4
JSR
BCC
TAY
BEQ
LDA
LDY
TSTEND
:XR1
FR0+1
FR0
TEST END OF STMT
BR IF NOT END
RESTORE TO LN=0
GET LINE NO.
LOAD LINE NO.
B27E 85B8
B280 84B7
B282 60
:XR2 STA DATALN+1
STY DATALN
RTS
SET LINE
DONE
XREAD — Execute READ Statement
B283
XREAD
B283
A5A8
LDA
ST INDEX
B285
48
PHA
B286
20C7B6
JSR
XGS
B289
A5B7
LDA
DATALN
B28B
85A0
STA
TSLNUM
B28D
A5B8
LDA
DATALN+1
B28F
85A1
STA
TSLNUM+1
SAVE STINDEX
SAVE READ STMT VIA GOSUB
MOVE DATALN TO TSLNUM
211
Source Code
B291 20A2A9
B294
A58A
LDA
B296
85F3
STA
B298
A58B
LDA
B29A
85F4
STA
B29C
2019B7
JSR
B29F
68
PLA
B2A0
85A8
STA
B2A2
:XRD1
B2A2
A000
LDY
B2A4
84F2
STY
B2A6
2007B3
JSR
B2A9
85B7
STA
B2AB
2005B3
JSR
B2AE
85B8
STA
B2B0
2005B3
JSR
B2B3
85F5
STA
B2B5
:XRD2
B2B5
2005B3
JSR
B2B8
85F6
STA
B2BA
2005B3
JSR
B2BD
C901
CMP
B2BF
F026 ~B2E7
BEQ
B2C1
A4F6
LDY
B2C3
C4F5
CPY
B2C5
B005 ~B2CC
BCS
B2C7
88
DEY
B2C8
84F2
STY
B2CA
90E9 "B2B5
BCC
GETSTMT
STMCUR
INBUFF
STMCUR+1
INBUFF+1
XRTN
STINDEX
#0
CIX
:XRNT1
DATALN
:XRNT
DATALN+1
:XRNT
ZTEMP1
:XRNT
ZTEMP1+1
:XRNT
#CDATA
:XRD4
ZTEMP1+1
ZTEMP1
:XRD2A
CIX
:XRD2
GO FIND TSLNUM
MOVE STMCUR TO INBUFF
RESTORE READ STMT VIA RETURN
GET SAVED STINDEX
SET IT
SET CIX=0
SET CIX
GET LINE NO. LOW
SET LINE NO. LOW
SET LINE NO. HIGH
SET LINE LENGTH
SET STMT LENGTH
GET STMT LINE TOKEN
IS IT DATA
BR IF DATA
GET DISPL TO NEXT STMT
IS IT EOL
BR IF EOL
SET NEW DISPL
AND CONTINUE THIS STMT
B2CC 84F2
B2CE C6F2
B2D0 A001
B2D2 B1F3
B2D4 303D "B313
:XRD2A STY CIX
DEC CIX
:XRD3 LDY #1
LDA [INBUFFLY
BMI :XROOD
WAS THIS STMT THE
DIRECT ONE
BR IF IT WAS [OUT OF DATA]
B2D6
38
SEC
B2D7
A5F2
LDA
CIX
B2D9
65F3
ADC
INBUFF
B2DB
85F3
STA
INBUFF
B2DD
A900
LDA
#0
B2DF
85B6
STA
DATAD
B2E1
65F4
ADC
INBUFF+1
B2E3
85F4
STA
INBUFF+1
B2E5
90BB
"B2A2
BCC
:XRD1
B2E7
:XRD4
B2E7
A900
LDA
*0
B2E9
85F5
STA
ZTEMP1
B2EB
:XRD5
B2EB
A5F5
LDA
ZTEMP1
B2ED
C5B6
CMP
DATAD
B2EF
B00B
*B2FC
BCS
:XRD7
B2F1
2005B3
:XRD6 JSR
:XRNT
B2F4
D0FB
~B2F1
BNE
:XRD6
B2F6
B0D8
"B2D0
BCS
:XRD3
B2F8
E6F5
INC
ZTEMP1
B2FA
D0EF
~B2EB
BNE
:XRD5
INBUFF + CIX + 1
= ADR NEXT PGM LINE
GO SCAN THIS NEXT LINE
I CLEAR ELEMENT COUNT
GET ELEMENT COUNT
AT PROPER ELEMENT
BR IF AT
ELSE SCAN FOR NEXT
GET CHAR
BR IF NOT CR OR COMMA
BR IF CR
INC ELEMENT COUNT
AND GO NEXT
B2FC A940
B2FE 85A6
B300 E6F2
:XRD7 LDA #$40
STA DIRFLG
INC CIX
SET READ BIT
INC OVER DATA TOKEN
212
Source Code
B302 4C35B3
B305
B305
E6F2
B307
A4F2 :
B309
B1F3
B30B
C92C
B30D
18
B30E
F002 "B312
B310
C99B
B312
60 :
B313
2034B9 ':
JMP
:XINA
XRNT
INC
CIX
XRNT1
LDY
CIX
LDA
[INBUFF],Y
CMP
#52C
CLC
BEQ
:XRNT2
CMP
#CR
XRNT2
RTS
XROOD
JSR
ERROOD
; GO DO IT
INC INDEX
GET INDEX
GET CHAR COUNT
IS IT A COMMA
CARRY CLEAR FOR COMMA
BR IF COMMA
IS IT CR
XINPUT — Execute INPUT
B3I6 XINPUT
B316
A93F
LDA
#'?'
B318
85C2
STA
PROMPT
B31A
203EAB
JSR
GETTOK
B31D
C6A8
DEC
STINDEX
B31F
9005 "B326
BCC
:XIN0
B321
2002BD
JSR
GIOPRM
B324
85B4
STA
ENTDTD
B326
:XIN0
B326
2051DA
JSR
INTLBF
B329
2089BA
JSR
GLINE
B32C
204EB3
JSR
:XITB
B32F
A000
LDY
#0
B331
84A6
STY
DIRFLG
B333
84F2
STY
CIX
B335
:XINA
B335
203EAB
JSR
GETTOK
B338
E6A8
INC
STINDEX
B33A
A5D2
LDA
VTYPE
B33C
3020 ~B35E
BMI
:XISTR
B33E
2000D8
JSR
CVAFP
B341
B014 "B357
BCS
:XIERR
B343
2007B3
JSR
:XRNT1
B346
D00F "B357
BNE
.-XIERR
B348
2016AC
JSR
RTNVAR
B34B
4C89B3
JMP
:XINX
B34E
20F4A9
:XITB JSR
TSTBRK
B351
D001 "B354
BNE
XITBT
B353
60
RTS
B354
4C93B7
XITBT JMP
XSTOP
B357
A900
: XI ERR LDA
*0
B359
85B4
STA
ENTDTD
B35B
2030B9
JSR
ERRINP
B35E
:XISTR
B35E
202EAB
JSR
EXPINT
B361
20BAAB
JSR
ARGPUSH
B364
C6F2
DEC
CIX
B366
A5F2
LDA
CIX
B368
85F5
STA
ZTEMP1
B36A
A2FF
LDX
#$FF
B36C
E8
:XIS1 INX
B36D
2005B3
JSR
:XRNT
B370
D0FA "B36C
BNE
:XIS1
B372
B004 ~B378
BCS
:XIS2
B374
24A6
BIT
DIRFLG
B376
50F4 ~B36C
BVC
:XIS1
SET PROMPT CHAR
GET FIRST TOKEN
BACK UP OVER IT
BR IF NOT OPERATOR
GO GET DEVICE NUM
SET DEVICE NO.
GO GET INPUT LINE
TEST BREAK
SET INPUT MODE
SET CIX=0
GO GET TOKEN
INC OVER TOKEN
IS A STR
BR IF STRING
CONVERT TO FP
GET END TOKEN
ERROR IF NO CR OR COMMA
RETURN VAR
GO FIGURE OUT WHAT TO DO
NEXT
GO TEST BREAK
BR IF BRK
DONE
STOP
RESET
ENTER DVC
GO ERROR
INIT EXECUTE EXPR
PUSH THE STRING
DEC CIX TO CHAR
BEFORE SOS
SAVE THAT CIX
SET CHAR COUNT = -1
INC CHAR COUNT
GET NEXT CHAR
BR NOT CR OR COMMA
BR IF CR
IS IT COMMA, IF NOT READ
THEN CONTINUE
213
Source Code
B378
A4P5
:XIS2
LDY
ZTEMPI
B37A
A5A8
LDA
STINDEX
B37C
48
PHA
B37D
8A
TXA
B37E
A2F3
LDX
(tINBUFF
B380
2064AB
JSR
RISC
B383
68
PLA
B384
85A8
STA
STINDEX
B386
20A6AE
JSR
RISASN
B389
24A6
:XINX
BIT
DIRFLG
B38B
500F ~B39C
BVC
:XIN
B38D
E6B6
INC
DATAD
B38F
2010B9
JSR
TSTEND
B392
B00D "B3A1
BCS
:XIRTS
B394
2007B3
:XIR1
JSR
:XRNT1
B397
9018 "B3B1
BCC
:XINC
B399
4CD0B2
JMP
:XRD3
B39C
:XIN
B39C
2010B9
JSR
TSTEND
B39F
9008 "B3A9
BCC
:XIN1
B3A1
2051DA
:XIRTS
JSR
INTLBF
B3A4
A900
LDA
#0
B3A6
85B4
STA
ENTDTD
B3A8
60
RTS
B3A9
2007B3
:XIN1
JSR
:XRNT1
B3AC
9003 ~B3B1
BCC
:XINC
B3AE
4C26B3
JMP
:XIN0
GET SAVED INDEX
SAVE INDEX
ACU = CHAR COUNT
POINT TO INBUFF
GO MAKE STR VAR
RESTORE INDEX
THEN DO STA ASSIGN
IS THIS READ
BR IF NOT
INC DATA DISPL
TEST END READ STMT
BR IF READ END
GET END DATA CHAR
BR IF COMMA
GO GET NEXT DATA LINE
RESTORE LBUFF
RESTORE ENTER
DEVICE TO ZERO
DONE
IF NOT END OF DATA
THEN BRANCH
AND CONTINUE
B3B1 E6F2
B3B3 4C35B3
:XINC INC CIX
JMP :XINA
INC INDEX
AND CONTINUE
XPRINT — Execute PRINT Statement
B3B6
B3B6
A5C9
B3B8
85AF
B3BA
A900
B3BC
8594
B3BE
A4A8
B3C0
B18A
B3C2
C912
B3C4
F053
"B419
B3C6
C916
B3C8
F07C
"B446
B3CA
C914
B3CC
F078
"B446
B3CE
C9I5
B3D0
F06F
"B441
B3D2
C91C
B3D4
F061
"B437
B3D6
20E0AA
B3D9
20F2AB
B3DC
C6A8
B3DE
24D2
B3E0
3016
"B3F8
B3E2
20E6D8
B3E5
A900
B3E7
85F2
XPRINT
LDA
STA
LDA
STA
PTABW
SCANT
#0
COX
:XPR0 LDY STINDEX
LDA [STMCUR],Y
CMP
#CCOM
BEQ
:XPTAB
CMP
#CCR
BEQ
:XPEOL
CMP
#CEOS
BEQ
:XPEOL
CMP
#CSC
BEQ
: XPNULL
CMP
JCPND
BEQ
:XPRIOD
JSR
EXEXPR
JSR
ARGPOP
DEC
STINDEX
BIT
VTYPE
BMI
:XPSTR
JSR
CVFASC
LDA
#0
STA
CIX
GET TAB VALUE
SCANT
SET OUT INDEX
GET STMT DISPL
GET TOKEN
BR IF TAB
BR IF EOL
BR IF EOL
BR IF NULL
GO EVALUATE EXPRESSION
POP FINAL VALUE
DEC STINDEX
IS THIS A STRING
BR IF STRING
CONVERT TO ASCII
B3E9 A4F2
OUTPUT ASCII CHARACTERS
214
Source Code
B3EB
B3ED
B3EE
B3F0
B3F3
B3F4
B3F6
B3F8
B3F8
B3FB
B3FD
B3FF
B401
B403
B405
B407
B409
B40B
B40D
B40F
B411
B413
B413
B416
B1F3
48
E6F2
205DB4
68
10F3 "B3E9
30C6 ~B3BE
209BAB
A900
85F2
A5D6
D004 "B407
C6D7
30B7 "B3BE
C6D6
A4F2
B1D4
E6F2
D002 ~B413
E6D5
205FB4
4CFFB3
LDA
PHA
INC
JSR
PLA
BPL
BMI
XPSTR
JSR
LDA
STA
XPR2C
BNE
DEC
BMI
XPR2B
XPR2
LDA
INC
BNE
INC
:XPR2A
JSR
JMP
[INBUFF], Y
CIX
:XPRC
:XPR1
:XPR0
GSTRAD
#0
CIX
VTYPE+EVSLEN
:XPR2B
VTYPE+EVSLEN+1
:XPR0
VTYPE+EVSLEN
CIX i
[VTYPE+EVSADR],Y
CIX ;
:XPR2A
VTYPE+EVSADR+1
:XPRC1
:XPR2C
FROM INBUFF
UNTIL THE CHAR
WITH THE MSB ON
IS FOUND
THEN GO FOR NEXT TOKEN
GO GET ABS STRING ARRAY
; IF LEN LOW
NOT ZERO BR
DEC LEN HI
BR IF DONE
; DEC LEN LOW
OUTPUT STRING CHARS
; FOR THE LENGTH
OF THE STRING
~
B419
B419
B41B
B41C
B41E
B420
B421
B423
B42 5
B427
B429
B42B
B42D
B42F
B431
B434
B437
B43A
B43C
B43E
B441
B441
B443
B446
B446
B448
B449
B44B
B44D
B44F
B451
B453
B455
B458
B458
B45A
B45C
A494
C8
C4AF
9009
18
A5C9
65AF
85AF
90F0
B419
A494
C4AF
B012 "B441
A920
205DB4
4C29B4
2002BD
85B5
C6A8
4CBEB3
E6A8
4CBEB3
A4A8
88
B18A
C915
F009 "E
C912
F005 ~E
A99B
205FB4
A900
85B5
60
:XPTAB
:XPR3 LDY
I NY
CPY
BCC
:XPIC3 CLC
LDA
ADC
STA
BCC
SCANT
:XPR4
PTABW
SCANT
SCANT
:XPR3
: XPR4 LDY COX
CPY SCANT
BCS :XPR4A
LDA #$20
JSR :XPRC
JMP :XPR4
:XPRIOD JSR GIOPRM
STA LISTDTD
DEC STINDEX
JMP :XPR0
B45D 297F
B45F E694
XPR4A
XPNULL
INC
STINDEX
JMP
:XPR0
XPEOL
XPEOS
LDY
STINDEX
DEY
LDA
[STMCUR],Y
CMP
#CSC
BEQ
: XPRTN
CMP
#CCOM
BEQ
: XPRTN
LDA
#CR
JSR
:XPRC1
XPRTN
LDA
#0
STA
LISTDTD
RTS
XPRC
AND
#?7F
XPRC1
INC
COX
DO UNTIL COX+1 < SCANT
SCANT = SCANT+TAB
DO UNTIL COX = SCANT
PRINT BLANKS
GET DEVICE NO.
SET AS LIT DEVICE
DEC INDEX
GET NEXT TOKEN
INC STINDEX
AT END OF PRINT
IF PREV CHAR WAS
SEMI COLON THEN DONE
ELSE PRINT A CR
OR A COMMA
THEN DONE
THEN DONE
SET PRIMARY
LIST DVC =
AND RETURN
MSB OFF
INC OUT INDEX
215
Source Code
B461 4C9FBA
OUTPUT CHAR
XLPRINT- Print to Printer
B464
XLPRINT
B464
A980
LDA
SPSTRS.255
POINT TO FILE SPEC
B466
85F3
STA
INBUFF
X
B468
A9B4
LDA
#PSTR/256
X
B46A
B5F4
STA
INBUFF+1
X
B46C
A207
LDX
#7
GET DEVICE
B46E
86B5
STX
LISTDTD
SET LIST DEVICE
B470
A900
LDA
#0
GET AUX 2
B47 2
A008
LDY
#8
GET OPEN TYPE
B474
20D1BB
JSR
SOPEN
DO OPEN
B477
20B3BC
JSR
IOTEST
TEST FOR ERROR
B47A
20B6B3
JSR
XPRINT
DO THE PRINT
B47D
4CF1BC
JMP
CLSYS1
CLOSE DEVICE
B480
50
PSTR DB
ipi
B481
3A9B
DB
' : ' ,CR
XLIST
— Execute LIST Command
B483
XLIST
B483
A000
LDY
#0
SET TABLE SEARCH LINE NO
B485
84A0
STY
TSLNUM
TO ZERO
B487
84A1
STY
TSLNUM+1
B489
88
DEY
B48A
84AD
STY
LELNUM
SET LIST END LINE NO
B48C
A97F
LDA
#57F
TO $7FFF
B48E
85AE
STA
LELNUM+1
B490
8DFE02
STA
$2FE
SET NON-DISPLAY MODE
B493
A99B
LDA
#CR
POINT CR
B495
209FBA
JSR
PRCHAR
B498
20C7B6
JSR
XGS
SAVE CURLINE VIA GOSUB
B49B
:XL0
B49B
A4A8
LDY
STINDEX
GET STMT INDEX
B49D
C8
I NY
INC TO NEXT CHAR
B49E
C4A7
CPY
NXTSTD
RT NEXT STMT
B4A0
B02D "B4CF
BCS
:LSTART
BR IF AT, NO PARMS
B4A2
A5A8
LDA
STINDEX
SAVE STINDEX
B4A4
48
PHA
ON STACK
B4A5
200FAC
JSR
POP1
POP FIRST ARGUMENT
B4A8
68
PLA
RESTORE STINDEX TO
B4A9
85A8
STA
STINDEX
RE-DO FIRST ARG
B4AB
A5D2
LDA
VTYPE
GET VAR TYPE
B4AD
1006 "B4B5
BPL
:XL1
BR IF NOT FILE SPEC STRING
B4AF
20D5BA
JSR
FLIST
GO OPEN FILE
B4B2
4C9BB4
JMP
:XL0
GO BACK TO AS IF FIRST PARM
B4B5
:XL1
B4B5
20D5AB
JSR
GETPINT
GO GET START LNO
B4B8
85A1
STA
TSLNUM+1
B4BA
A5D4
LDA
FR0
MOVE START LNO
B4BC
85A0
STA
TSLNUM
TO TSLNUM
B4BE
A4A8
LDY
STINDEX
GET STMT INDEX
B4C0
C4A7
CPY
NXTSTD
AT NEXT STMT
B4C2
F003 "B4C7
BEQ
:LSE
BR IF AT, NO PARMS
216
Source Code
B4C4 20D5AB
GO GET LINE NO
B4C7
A5D4
:LSE
LDA
FR0
B4C9
85AD
STA
LELNUM
B4CB
A5D5
LDA
FR0+1 ;
B4CD
85AE
STA
LELNUM+1
B4CF
: LSTART
B4CF
20A2A9
JSR
GETSTMT
B4D2
20E2A9
:LNXT
JSR
TENDST ;
B4D5
3024 *
B4FB
BMI
: LRTN I
B4D7
A001
:LTERNG
LDY
#1
B4D9
B18A
LDA
[STMCUR],Y ;
B4DB
C5AE
CMP
LELNUM+1 ;
B4DD
900B "
B4EA
BCC
:LGO
B4DF
D01A *
B4FB
BNE
: LRTN
B4E1
88
DEY
B4E2
B18A
LDA
[STMCUR],Y
B4E4
C5AD
CMP
LELNUM
B4E6
9002 *
B4EA
BCC
:LGO
B4E8
D011 "
B4FB
BNE
:LRTN
B4EA
205CB5
:LGO
JSR
:LLINE ;
B4ED
20F4A9
JSR
TSTBRK ;
B4F0
D009 *
B4FB
BNE
: LRTN ;
B4F2
20DDA9
JSR
GETLL
B4F5
20D0A9
JSR
GNXTL ;
B4F8
4CD2B4
JMP
:LNXT ;
B4FB
:LRTN
B4FB
A5B5
LDA
LISTDTD ;
B4FD
F007 "
3506
BEQ
: LRTN1 ;
B4FF
20F1BC
JSR
CLSYSD ;
B502
A900
LDA
#0
B504
85B5
STA
LISTDTD
B506
:LRTN1
B506
8DFE02
STA
S2FE ;
B509
4C19B7
JMP
XRTN ;
MOVE END LINE NO
TO LIST END LINE NO
GO FIND FIRST LINE
AT END OF STMTS
BR AT END
COMPARE CURRENT STMT
LINE NO WITH END
LINE NO
GO LIST THE LINE
TEST FOR BREAK
BR IF BREAK
GO INC TO NEXT LINE
GO DO THIS LINE
IF LIST DEVICE
IS ZERO, BR
ELSE CLOSE DEVICE
AND RESET
DEVICE TO ZERO
SET DISPLAY MODE
THEN RESTORE LIST LINE
AND RETURN
LSCAN — Scan a Table for LIST Token
B50C
B50C 86AA
B50E 2030B5
B511 A4AA
B513 C6AF
B515 300E
'B525
LSCAN
STX
JSR
LSC0
DEC
BMI
ENTRY PARMS
X = SKIP LENGTH
A,Y = TABLE ADR
SCANT = TOKEN
SRCSKP
:LSST
SCANT
:LSINC
SAVE SKIP LENGTH
SAVE SRC ADR
GET SKIP FACTOR
DECREMENT SRC COUNT
BR IF DONE
B517
B5I9
B51B
B51C
B51E
B51F
B522
B195
3003 "B51E
C8
D0F9 "B517
C8
2025B5
4C11B5
:LSC1 LDA
BMI
INY
BNE
:LSC2 INY
JSR
JMP
CSRCADR], Y
:LSC2
:LSINC
:LSC0
; GET CHARACTER
BR IF LAST CHARACTER
INC TO NEXT
BR ALWAYS
INC TO AFTER LAST CHAR
INC SRC ADR BY Y
GO TRY NEXT
B525 18
B526 98
B527 6595
B529 8595
:LSINC CLC
TYA
ADC SRCADR
STA SRCADR
Y PLUS
SRCADR
IS
217
Source Code
B52B
A8
TAY
B52C
A596
LDA
SRCADR+1 ;
B52E
6900
ADC
#0
B530
8596
': LSST
STA
SRCADR+1 ;
B532
8495
STY
SRC ADR
B534
60
RTS
LPRTOKEN — Print
a Token
B535
LPRTOKEN
B535
: LPRTOKEN
B535
A0FF
LDY
#?FF
B537
84AF
STY
SCANT
B539
E6AF
:LPT1
INC
SCANT ;
B53B
A4AF
LDY
SCANT ;
B53D
B195
LDA
[SRCADR],Y ,-
B53F
48
PHA
B540
C99B
CMP
#cr ;
B542
F004 "B548
BEQ
:LPT1A J
B544
297F
AND
#$7F ;
B546
F003 "B54B
BEQ
:LPT2 ;
B548
:LPT1A
B548
209FBA
JSR
PRCHAR ,-
B54B
:LPT2
B54B
68
PLA
B54C
10EB "B539
BPL
: LPT1
B54E
60
RTS
LPTWB — Print Token with Bla
nk Before and After
B54F
: LPTWB
B54F
A920
LDA
#$20
B551
209FBA
JSR
PRCHAR
B554
2035B5
: LPTTB
JSR
: LPRTOKEN
B557
A920
:LPBLNK
LDA
#?20
B559
4C9FBA
JMP
PRCHAR
NEW
SRCADR
STORE NEW SRCADR
AND
RETURN
INITIALIZE INDEX TO ZERO
INC INDEX
GET INDEX
GET TOKEN CHAR
SAVE CHAR
IF ATARI CR
THEN DON'T AND
TURN OFF MSB
BR IF NON-PRINTING
GO PRINT CHAR
GET CHAR
BR IF NOT END CHAR
GO BACK TO MY BOSS
GET BLANK
GO PRINT IT
GO PRINT TOKEN
GET BLANK
GO PRINT IT AND RETURN
LLINE — List a Line
B55C
LLINE
B55C
: LLINE
B55C
A000
LDY
#0
B55E
B18A
LDA
[STMCUR]
Y
MOVE LINE NO
B560
85D4
STA
FR0
TO FR0
B562
C8
I NY
B563
B18A
LDA
[STMCUR]
Y
B565
85D5
STA
FR0+1
B567
20AAD9
JSR
CVIFP
CONVERT TO FP
B56A
20E6D8
JSR
CVFASC
CONVERT TO ASCII
B56D
A5F3
LDA
INBUFF
MOVE INBUFF ADR
B56F
8595
STA
SRCADR
TO SRCADR
B571
A5F4
LDA
INBUFF+I
B573
8596
STA
SRCADR+1
B575
2054B5
JSR
: LPTTB
AND
PRINT LINE NO
B578
LDLINE
B578
A002
LDY
#2
B57A
B18A
LDA
[STMCUR]
Y
GET
LINE LENGTH
B57C
859F
STA
LLNGTH
AND
SAVE
B57E
C8
I NY
B57F
B18A
:LL1 LDA
[STMCUR], Y
j
C-ET STMT LENGTH
B581
85A7
STA
NXTSTD
AND
SAVE AS NEXT ST DISPL
B583
C8
INY
INC
TO STMT TYPE
B584
84A8
STY
STINDEX
AND
SAVE DISPL
B586
2090B5
JSR
:LSTMT
GO LIST STMT
218
Source Code
B589
A4A7
LDY
NXTSTD
B58B
C49F
CPY
LLNGTH
B58D
90F0
"B57F
BCC
:LL1
B58F
60
RTS
DONE LINE
BR IF NOT
ELSE RETURN
LSTMT — List a Statement
B590
: LSTMT
B590
203IB6
JSR
:LGCT
B593
C936
CMP
#CILET
B595
F017 "B5AE
BEQ
:LADV
B597
203DB6
JSR
LSTMC
B59A
2031B6
JSR
:LGCT
B59D
C937
CMP
#CERR
B59F
F004 "B5A5
BEQ
:LDR
B5A1
C902
CMP
#2
B5A3
B009 ~B5AE
BCS
:LADV
B5A5
202FB6
:LDR JSR
:LGNT
B5A8
209FBA
JSR
PRCHAR
B5AB
4CA5B5
JMP
:LDR
B5AE
202FB6
: LADV JSR
:LGNT
B5BI
101A ~B5CD
BPL
:LNVAR
B5B3
297F
AND
#$7F
B5B5
85AF
STA
SCANT
B5B7
A200
LDX
#0
B5B9
A583
LDA
VNTP+1
B5BB
A482
LDY
VNTP
B5BD
200CB5
JSR
:LSCAN
B5C0
2035B5
:LS1 JSR
:LPRTOKEN
B5C3
C9A8
CMP
#$A8
B5C5
D0E7 "B5AE
BNE
:LADV
B5C7
202FB6
JSR
:LGNT
B5CA
4CAEB5
JMP
:LADV
B5CD
:LNVAR
B5CD
C90F
CMP
#$0F
B5CF
F018 "B5E9
BEQ
:LSTC
B5D1 B036 "B609
B5D3
204DAB
JSR
NCTOFR0
B5D6
C6A8
DEC
STINDEX
B5D8
20E6D8
JSR
CVFASC
B5DB
A5F3
LDA
INBUFF
B5DD
8595
STA
SRCADR
B5DF
A5F4
LDA
INBUFF+1
B5E1
8596
STA
SRCADR+1
B5E3
2035B5
:LSX
JSR
rLPRTOKEN
B5E6
4CAEB5
JMP
:LADV
B5E9
202FB6
:LSTC
JSR
:LGNT
B5EC
85AF
STA
SCANT
B5EE
A922
LDA
#$22
B5F0
209FBA
JSR
PRCHAR
B5F3
A5AF
LDA
SCANT
B5F5
F00A "B601
BEQ
:LS3
GET CURRENT TOKEN
IF IMP LET
BR
GO LIST STMT CODE
GO GET CURRENT TOKEN
BR IF ERROR STMT
WAS IT DATA OR REM
BR IF NOT
OUTPUT DATA/REM
THEN PRINT THE CR
GET NEXT TOKEN
BR IF NOT VARIABLE
TURN OFF MSB
AND SET AS SCAN COUNT
SCAN VNT FOR
VAR NAME
PRINT VAR NAME
NAME END IN LPAREN
BR IF NOT
DON'T PRINT NEXT TOKEN
IF IT IS A PAREN
TOKEN: ?0F
BR IF 0F, STR CONST
BR IF TOKEN >$0F
ELSE IT'S NUM CONST
GO MOVE FR0
BACK INDEX TO LAST CHAR
CONVERT FR0 TO ASCII
POINT SCRADR
TO INBUFF WHERE
CHAR IS
GO PRINT NUMBER
GO FOR NEXT TOKEN
GET NEXT TOKEN
WHICH IS STR LENGTH
PRINT DOUBLE QUOTE CHAR
B5F7 202FB6
B5FA 209FBA
B5FD C6AF
B5FF D0F6 "B5F7
:LS2 JSR :LGNT
JSR PRCHAR
DEC SCANT
BNE :LS2
OUTPUT STR CONST
CHAR BY CHAR
UNTIL COUNT =0
B601
B601 A922
B603 209FBA
B606 4CAEB5
:LS3
LDA
JSR
JMP
#$22
PRCHAR
:LADV
THEN OUTPUT CLOSING
DOUBLE QUOTE
219
Source Code
B609
38
:LOP SEC
B60A
E910
SBC
#510
B60C
85AF
STA
SCANT
B60E
A200
LDX
#0
B610
A9A7
LDA
#OPNTAB/256
B612
A0E3
LDY
#OPNTAB&255
B614
200CBS
JSR
:LSCAN
B617
2031B6
JSR
:LGCT
B61A
C93D
CMP
#CFFUN
B61C
B0C5 "B5E3
BCS
:LSX
B61E
A000
LDY
#0
B620
B195
LDA
[SRCADRJ.Y
B622
297F
AND
#$7F
B624
20F7A3
JSR
TSTALPH
B627
B0BA "B5E3
BCS
:LSX
B629
204FB5
JSR
:LPTWB
B62C
4CAEB5
JMP
:LADV
B62F
:LGNT
B62F
E6A8
INC
STINDEX
B631
A4A8
: LGCT LDY
STINDEX
B633
C4A7
CPY
NXTSTD
B635
B003 "B63A
BCS
: LGNTE
B637
B18A
LDA
[STMCUR],Y
B639
60
RTS
B63A
60
: LGNTE PLA
B63B
68
PLA
B63C
60
RTS
B63D
LSTMC
B63D
85AF
STA
SCANT
B63F
A202
LDX
#2
B641
A9A4
LDA
fSNTAB/256
B643
A0AF
LDY
#SNTAB&255
B645
200CB5
JSR
:LSCAN
B648
4C54B5
JMP
: LPTTB
SUBSTRACT THE 10
SET FOR SCAN COUNT
SCAN OP NAME TABLE
GO GET CURRENT TOKEN
IS IT FUNCTION
BR IF FUNCTION
GET FIRST CHAR
TURN OFF MSB
TEST FOR ALPHA
BR NOT ALPHA
LIST ALPHA WITH
BLANKS FOR AND AFTER
GET NEXT TOKEN
INC TO NEXT
GET DISPL
AT END OF STMT
BR IF AT END
GET TOKEN
AND RETURN
POP CALLERS ADR
AND
GO BACK TO LIST LINE
SET INSCAN COUNT
AND
STATEMENT NAME TABLE
GO LIST WITH FOLLOWING BLANK
XFOR — Execute FOR
B64B
B64B
B64B
208AB8
B64E
20E0AA
B651
A5D3
B653
0980
B655
48
B656
2025B8
JSR
: SAVDEX
JSR
EXEXPR
LDA
VNUM
ORA
#$80
PHA
JSR
FIXRSTK
SAVE STINDEX
DO ASSIGNMENT
GET VARIABLE #
OR IN HIGH ORDER BIT
SAVE ON CPU STACK
FIX RUN STACK
BUILD STACK ELEMENT
B659
A90C
LDA
#FBODY
B65B
2078B8
JSR
: REXPAN
B65E
200FAC
JSR
POP1
;
!
PUT
LIMIT [
B661
A2D4
LDX
#FR0
B663
A000
LDY
#FLIM
B665
208FB8
JSR
:MV6RS
; GET # OF BYTES
; EXPAND RUN STACK
; EVAL EXP & GET INTO FR0
POINT TO FR0
GET DISPL
GO MOVE LIMIT
SET DEFAULT STEP
B668 2044DA
B66B A901
B66D 85D5
B66F A940
B671 85D4
JSR
ZFR0
LDA
#1
STA
FR0 + 1
LDA
#$40
STA
FR0
CLEAR FR0 TO ZEROS
GET DEFAULT STEP
SET DEFAULT STEP VALUE
GET DEFAULT EXPONENT
STORE
220
Source Code
TEST FOR END OF STMT
B673 2010B9
B676 B003 "B67B
B678 200FAC
B67B
B67B A2D4
B67D A006
B67F 208FB8
JSR
BCS
TSTEND
:NSTEP
JSR
:NSTEP
ELSE GET STEP VALUE
POP1
TEST FOR END OF START
IF YES, WE ARE AT END OF
STMT
EVAL EXP & GET INTO FR0
PUT STEP [IN FR0] ON STACK
LDX
#FR0
LDY
#FSTEP
JSR
:MV6RS
POINT TO FR0
GET DISPL
GO MOVE STEP
B682 68
B683
'SHRSTK
EXPAND RUN STACK
B683
48
PHA
B684
A904
LDA
#GFHEAD ;
B686
2078B8
JSR
: REXPAN ;
PUT ELEMENT ON STACK
B689
68
PLA
B68A
A000
LDY
#GFTYPE ;
B68C
91C4
STA
[TEMPA],Y ;
B68E
B18A
LDA
[STMCUR],Y
B690
C8
INY
B691
91C4
STA
[TEMPA],Y
B693
B18A
LDA
[STMCUR],Y ;
B695
C8
INY
B696
91C4
STA
[TEMPA],Y ;
B698
A6B3
LDX
SAVDEX ;
B69A
CA
DEX
B69B
8A
TXA
B69C
C8
INY
B69D
91C4
STA
[TEMPA],Y ;
B69F
60
RTS
; GET VARIABLE #
PSHRSTK - PUSH COMMON PORT OF FOR/GOSUB
- ELEMENT ON RUN STACK
ON ENTRY A - VARIABLE # OR [FOR GOSUB]
TSLNUM - LINE #
STINDEX - DISPL TO STMT TOKEN +1
SAVE VAR # / TYPE
GET # OF BYTES TO EXPAND
EXPAND [OLD TOP RETURN IN
ZTEMP1]
GET VARIABLE #/TYPE
GET DISPL TO TYPE IN HEADER
PUT VAR#/TYPE ON STACK
GET LINE # LOW
POINT TO NEXT HEADER BYTE
PUT LINE # LOW IN HEADER
GET LINE # HIGH
PUT IN HEADER
GET SAVED INDEX INTO LINE
POINT TO TOKEN IN LINE
PUT IN A
POINT TO DISPL IN HEADER
PUT IN HEADER
XGOSUB — Execute GOSUB
B6A0
B6A0 20C7B6
XGOSUB
JSR
GO TO XGS ROUTINE
XGOTO — Execute GOTO
B6A3 XGOTO
B6A3 20D5AB JSR
B6A6
B6A6 A5D5
B6A8 85A1
B6AA A5D4
B6AC 85A0
GETPINT ; GET POSTIVE INTEGER IN FR0
GET LINE ADRS & POINTERS
X
X
PUT LINE # IN TSLNUM
X
LDA
FR0 + 1
STA
TSLNUM+1
LDA
FR0
STA
TSLNUM
221
Source Code
B6AE
XG01
B6AE
20A2A9
JSR
GETSTMT
B6B1
B005 "B6B8
BCS
:ERLN
B6B3
68
PLA
B6B4
68
PLA
B6B5
4C5FA9
JMP
EXECNL
B6B8
:ERLN
B6B8
20BEB6
JSR
RESCUR
; LINE POINTERS AND STMT ADDRESS
; IF NOT FOUND ERROR
; CLEAN UP STACK
; GO TO EXECUTE CONTROL
RESTORE STMT CURRENT
B6BB 2028B
B6BE
B6BE A5BE
B6C0 858A
B6C2 A5BF
B6C4 858B
B6C6 60
XGS — Perform GOSUB [GOSUB, LIST, READ]
XGS
JSR
ERNOLN
RESCUR
LDA
SAVCUR
STA
STMCUR
LDA
SAVCUR+1
STA
STMCUR+1
RTS
208AB8
B6C7
B6C7
B6CA
B6CA A900
B6CC 4C83B6
XGS I
JSR
: SAVDEX
LDA
#0
JMP
PSHRSTK
LINE # NOT FOUND
RESTORE STMCUR
X
X
X
GET STMT INDEX
GET GOSUB TYPE
PUT ELEMENT ON RUN STACK
XNEXT— Execute NEXT
B6CF XNEXT
B6CF A4A8
B6D1 B18A
B6D3 85C7
B6D5
B6D5 2041B8
B6D8 B03C "B716
B6DA F03A ~B716
B6DC C5C7
B6DE D0F5 "B6D5
LDY
LDA
STA
GET VARIABLE #
STINDEX
[ STMCUR ],Y
ZTEMP2+1
GET ELEMENT
BCS
BEQ
CMP
BNE
:ERNFOR
:ERNFOR
ZTEMP2+1
:XN
GET STMT INDEX
GET VARIABLE f
SAVE
PULL ELEMENT FROM RUN STACK
VAR#/TYPE RETURN IN A
IF AT TOP OF STACK, ERROR
IF TYPE = GOSUB, ERROR
DOES STKVAR* = OUR VAR #
GET STEP VALUES IN FR1
B6E0 A006
B6E2 209EB8
B6E5 A5E0
B6E7 48
LDY
JSR
#FSTEP
:PL6RS
GET DISPL INTO ELEMENT
GET STEP INTO FR1
SAVE TYPE OF STEP [+ OR -]
LDA
PHA
GET EXP FR1 [CONTAINS SIGN]
PUSH ON CPU STACK
B6E8 A5C7
B6EA 2089AB
B6ED 203BAD
B6F0 2016AC
GET VARIABLE VALUE
LDA
JSR
ZTEMP2+1
GETVAR
GET NEW VALUE
JSR
JSR
FRADD
RTNVAR
GET LIMIT IN FR1
,- GET VAR #
; GET VARIABLE VALUE
ADD STEP TO VALUE
PUT IN VARIABLE TABLE
222
Source Code
B6F3
A000
LDY
B6F5
209EB8
JSR
B6F8
68
PLA
B6F9
1006 "B701
BPL
B6FB
2035AD
JSR
B6FE
1009 ~B709
BPL
B700
60
RTS
#FLIM
:PL6RS
GET DISPL TO LIMIT IN ELEMENT
GET LIMIT INTO FR1
GET SIGN OF STEP
BR IF STEP +
COMPARE FOR NEGATIVE STEP
FRCMP
:NEXT
COMPARE VALUE TO LIMIT
IF VALUE >= LIMIT, CONTINUE
ELSE DONE
COMPARE FOR POSTIVE STEP
B701
:STPPL
B701
2035AD
JSR
FRCMP ;
B704
F003 "B709
BEQ
:NEXT ;
B706
3001 "B709
BMI
: NEXT ;
B708
60
RTS
B709
•NEXT
B709
A910
LDA
#GFHEAD+FBODY
B70B
2078B8
JSR
: REXPAND ;
B70E
2037B7
JSR
:GETTOK ;
B711
C908
CMP
#CFOR ;
B713
D032 "B747
BNE
:ERGFD ;
B715
60
RTS
B716
:ERNFOR
B716
2026B9
JSR
ERNOFOR
COMPARE VALUE TO LIMIT
IF = CONTINUE
IF < CONTINUE
ELSE RETURN
GET # BYTES IN FOR ELEMENT
GO PUT IT BACK ON STACK
GET TOKEN [RETURNS IN A]
IS TOKEN = FOR?
IF NOT IT'S AN ERROR
XRTN — Execute RETURN
B719
XRTN
B719
2041B8
JSR
POPRSTK ;
B71C
B016
"B734
BCS
:ERRTN ;
B71E
DBF 9
"B719
BNE
XRTN
B720
2037B7
JSR
:GETTOK ;
B723
C90C
CMP
#CGOSUB ;
B725
F00C
"B733
BEQ
: XRTS ;
B727
C91E
CMP
#CON
B729
F008
"B733
BEQ
:XRTS j
B72B
C904
CMP
#CLIST
B72D
F004
"B733
BEQ
:XRTS ;
B72F
C922
CMP
#CREAD ;
B731
D014
~B747
BNE
:ERGFD ,-
B733
:XRTS
B733
60
RTS
B734
:ERRTN
B734
2020B9
JSR
ERBRTN ;
GET ELEMENT FROM RUN STACK
IF AT TOP OF STACK, ERROR
IF TYPE NOT GOSUB, REPEAT
GET TOKEN FROM LINE [IN A]
IS IT GOSUB?
BR IF GOSUB
BR IF ON
BR IF LIST
MAYBE IT'S READ
IF NOT, ERROR
BAD RETURN ERROR
:GETTOK - GET TOKEN POINTED TO BY RUN STACK ELEMENT
ON EXIT A - CONTAINS TOKEN
B737
:GETTOK
B737
2018B8
JSR
SETLINE ;
B73A
B00B ~B747
BCS
:ERGFD
B73C
A4B2
LDY
SVDISP j
B73E
88
DEY
B73F
B18A
LDA
[STMCUR],Y ;
B741
85A7
STA
NXTSTD ;
B743
C8
I NY
B744
B18A
LDA
[STMCUR],Y ;
B746
B747
60
RTS
:ERGFD
SET UP TO PROCESS LINE
IF LINE # NOT FOUND, ERROR
GET DISPL TO TOKEN
POINT TO NXT STMT DISPL
GET NEXT STMT DISPL
SAVE
GET DISPL TO TOKEN AGAIN
GET TOKEN
223
Source Code
B747
20BEB6
JSR
RESCUR
B74A
2022B9
JSR
ERGFDEL
XRUN
— Execute RUN
B74D
XRUN
TEST FOR EN
B74D
2010B9
JSR
TSTEND
B750
B003 "B755
BCS
: NOFILE
B752
20F7BA
JSR
FRUN
B755
NOFILE
RESTORE STMT CURRENT
CHECK FOR END OF STMT
IF END OP STMT, BR
ELSE HAVE FILE NAME
GET 1ST LINE # OF PROGRAM
B755 A900
B757
85A0
STA
TSLNUM
B759
85A1
STA
TSLNUM+1
B75B
2018B8
JSR
SETLINE
B75E
20E2A9
JSR
TENDST
B761
3012 "B775
BMI
:RUNEND
B763
20F8B8
JSR
RUNINIT
GET SMALLEST POSSIBLE
LINE NUM
X
X
SET UP LINE POINTERS
TEST FOR END OF STMT TABLE
IF AT END, BR
CLEAR SOME STORAGE
FALL THRU TO CLR
XCLR — Execute CLR
B766
XCLR
B766
20C0B8
JSR
ZVAR
; GO ZERO VARS
B769
20AFB8
JSR
RSTPTR
; GO RESET STACK PTRS
B76C
A900
LDA
#0
; CLEAR DATA VALUES
B76E
85B7
STA.
DATALN
B770
85B8
STA
DATALN+1
B772
85B6
STA
DATAD
B774
60
RTS
B77S
: RUNEND
B775
4C50A0
JMP
SNX1
;NO PROGRAM TO RUN
X1F — Execute IF
B778
B778 200FAC
B77B A5D5
B77D F009 ~B788
B77F 2010B9
B782 B003 "B787
B784 4CA3B6
B787
B787 60
LDA
FR0M
BEQ
*
: FALSE
*
*
EXPRESSION TRUE
JSR
TSTEND
BCS
:TREOS
TRUE AND NOT EOS
JMP
XGOTO
TRUE AND EOS
:TREOS
EVAL EXP AND GET VALUE
INTO FR0
GET 1ST MANTISSA BYTE
IF = 0, # = AND IS FALSE
TEST FOR END OF STMT
IF AT EOS, BRANCH
JOIN GOTO
EXPRESSION FALSE
B788
B788 A59F
B78A 85A7
B78C 60
: FALSE
LDA LLNGTH
STA NXTSTD
RTS
GET DISPL TO END OF LINE
SAVE AS DISPL TO NEXT STMT
224
Source Code
XEND — Execute END
B78D
XEND
B78D
20A7B7
JSR
STOP
B790
4C50A0
JMP
SNX1
XSTOP — Execute STOP
B793
XSTOP
B793
20A7B7
JSR
STOP
• GO SET UP STOP LINE #
PRINT MESSAGE
B796
206EBD
JSR
PRCR
• PRINT CR
B799
A9B6
LDA
#:MSTOP5.255
■ SET POINTER FOR MESSAGE
B79B
8595
STA
SRCADR
• X
B79D
A9B7
LDA
#:MSTOP/256
• X
B79F
8596
STA
SRCADR+1
; x
B7A1
2035B5
JSR
LPRTOKEN
• PRINT IT
B7A4
4C74B9
;
JMP
:ERRM2
• PRINT REST OF MESSAGE
B7A7
STOP
B7A7
20E2A9
JSR
TENDST
• GET CURRENT LINE # HIGH
B7AA
3007 ~B7B3
BMI
:STOPEND
• IF -, THIS IS DIRECT STMT
• DON'T STOP
B7AC
85BB
STA
STOPLN+1
■ SAVE LINE # HIGH FOR CON
B7AE
88
DEY
• DEC INDEX
B7AF
B18A
LDA
[STMCUR],Y
; GET LINE # LOW
B7B1
85BA
STA
STOPLN
- SAVE FOR CON
B7B3
:STOPEND
B7B3
4C72BD
;
JMP
SETDZ
• SET L/D DEVICE =0
B7B6
53544F5050
TOP DC
'STOPPED '
4544A0
XCONT — Execute Continue
B7BE
XCONT
B7BE
20E2A9
JSR
TENDST
IS IT INDIRECT STMT?
B7C1
10F0 "B7B3
BPL
: STOPEND
IF YES, BR
B7C3
A5BA
LDA
STOPLN i
SET STOP LINE # AS LINE #
FOR GET
B7C5
85A0
STA
TSLNUM
X
B7C7
A5BB
LDA
STOPLN+1
X
B7C9
85A1
STA
TSLNUM+1
X
B7CB
20A2A9
JSR
GETSTMT
GET ADR OF STMT WE
STOPPED AT
B7CE
20E2A9
JSR
TENDST
AT END OF STMT TAB ?
B7D1
30A2 ~B775
BMI
: RUNEND
B7D3
20DDA9
JSR
GETLL
GET NEXT LINE ADDR IN CURSTM
B7D6
20D0A9
JSR
GNXTL
X
B7D9
20E2A9
JSR
TENDST
SEE IF WE ARE AT END OF
STMT TABLE
B7DC
3097 "B775
BMI
: RUNEND ;
BR IF MINUS
B7DE
4C1BB8
JMP
SETLN1 ;
SET UP LINE POINTERS
XTRAP — Execute TRAP
B7E1
XTRAP
B7E1
20E0AB
JSR
GET I NT
CONVERT LINE # TO POSITIVE
INT
B7E4
A5D4
LDA
FR0 ;
SAVE LINE # LOW AS TRAP LINE
B7E6
85BC
STA
TRAPLN ;
IN CASE OF LATER ERROR
B7E8
A5D5
LDA
FR0+1 ;
X
B7EA
85BD
STA
TRAPLN+1 ;
X
B7EC
60
RTS
225
Source Code
XON
— Execute ON
B7ED
XON
B7ED
208AB8
JSR
rSAVDEX i
B7F0
20E9AB
JSR
GET1INT j
B7F3
A5D4
LDA
FR0 J
B7F5
F020 "B817
BEO
:ERV ;
B7F7
A4A8
LDY
STINDEX ;
B7F9
88
DEY
B7FA
B18A
LDA
[STMCUR],Y ;
B7FC
C917
CMP
#CGTO ;
B7FE
F003 "B803
BEQ
:GO
THIS IS ON - GOSUB:
B800
20CAB6
JSR
XGS1 ,-
SAVE INDEX INTO LINE
GET 1 BYTE INTEGER
GET VALUE
IF ZERO, FALL THROUGH TO
NEXT STMT
GET STMT INDEX
BACK UP TO GOSUB/GOTO
GET CODE
IS IT GOTO?
IF YES, DON'T PUSH ON
RUN STACK
PUT ELEMENT ON RUN STACK
PUT ELEMENT ON RUN STACK
FOR RETURN
B803
:GO
B803
A5D4
LDA
FR0
B805
85B3
STA
ONLOOP
B807
:ONl
B807
20D5AB
JSR
GETPINT
B80A
C6B3
DEC
ONLOOP
B80C
F006 ~B814
BEQ
:ON2
B80E
2010B9
JSR
TSTEND
B811
90F4 "B807
BCC
:ONl
B813
60
RTS
B814
:ON2
B814
4CA6B6
JMP
XG02
B817
:ERV
B817
60
RTS
| GET INDEX INTO EXPRESSIONS
; SAVE FOR LOOP CONTROL
; GET + INTEGER
; IS THIS THE LINE # WE WANT?
| IF YES, GO DO IT
) ARE THERE MORE EXPRESSIONS
; IF YES, THEN EVAL NEXT ONE
; ELSE FALL THROUGH TO
NEXT STMT
,- JOIN GOTO
FALL THROUGH TO NEXT STMT.
Execution Control Statement Subroutines
SETLINE - Set Up Line Pointers
* ON ENTRY
* ON EXIT
TLSNUM - LINE #
STMCUR - CONTAIN PROPER VALUES
LLNGTH - X
NXTSTM - X
CARRY SET BY GETSTMT IF LINE # NOT FOUND
B81B
B818
20A2A9
B81B
B81B
A002
B81D
B18A
B81F
859F
B821
C8
B822
84A7
B824
60
FIXRSTK — Fix
SETLINE
JSR
GETSTMT
SETLN1
LDY
#2
LDA
[STMCUR], Y
STA
LLNGTH
INY
STY
NXTSTD
GET STMCUR
GET DISP IN LINE TO LENGTH
GET LINE LENGTH
SET LINE LENGTH
POINT TO NEXT STMT DISPL
SET NXT STMT DISPL
RTS
Run Stack — Remove Old FORs
* ON ENTRY A - VARIABLE # IN CURRENT FOR
*
* ON EXIT RUNSTK CLEAR OF ALL FOR ' S
226
Source Code
B825
B825 85C7
B827 2081B8
FIXRSTK
STA ZTEMP2+1 ; SAVE VAR # OF THIS FOR
SAVE TOP OF RUN STACK
JSR :SAVRTOP ; SAVE TOP OF RUN STACK IN
ZTEMP]
B82A :FIXR
B82A 2041B8 JSR
B82D B008 "B837 BCS
B82F F006 "B837 BEQ
B831 C5C7 CMP
B833 F00B "B840 BEQ
B835 D0F3 ~B82A
BNE
POPRSTK
:TOP
:TOP
ZTEMP2+1
: FNVAR
:FIXR
POP AN ELEMENT FROM RUNSTK
IF AT TOP - WE ARE DONE
IF CC = 08 ELEMENT WAS GOSUB
IS STK VAR # = OUR VAR #?
IF YES, WE ARE DONE
ELSE LOOK AT NEXT ELEMENT
B837
B837
A5C4
B839
8590
B83B
A5C5
B83D
8591
B83F
60
FOR VAR # NOT ON STACK ABOVE TOP OR GOSUB
[RESTORE TOP OF STACK]
LDA
STA
LDA
STA
RTS
TEMPA
TOPRSTK
TEMPA+1
TOPRSTK+1
RESTORE TOPRSTK
X
X
X
B840
B840
FOR VAR # FOUND ON STACK
: FNVAR
RTS
POPRSTK — Pop Element from Run Stack
A - TYPE OF ELEMENT OR VAR #
X - DISPL INTO LINE OF FOR/GOSUB TOKEN
CUSET - CARRY SET STACK WAS EMPTY
CARRY CLEAR - ENTRY POPED
EQ SET - ELEMENT IS GOSUB
TSLNUM - LINE #
B841
XPOP
B841
POPRSTK
B841
A58F
LDA
B843
C591
CMP
B845
9008
"B84F
BCC
B847
A58E
LDA
B849
C590
CMP
B84B
9002
"B84F
BCC
B84D
38
SEC
B84E
60
RTS
B84F
B84F A904
B851 2072BE
B854 A003
B856
B190
B858
85B2
B85A
88
B85B
B190
B85D
85A1
B85F
88
TEST FOR STACK EMPTY
RUNSTK+1
TOPRSTK+1
:NTOP
RUNSTK
TOPRSTK
:NTOP
GET 4 BYTE HEADER
NTOP
LDA
JSR
LDY
LDA
STA
DEY
LDA
STA
DEY
GET START OF RUN STACK HIGH
IS IT < TOP OF STACK HIGH
IF YES, WE ARE NOT AT TOP
GET START OF RUN STACK LOW
IS IT < TOP OF STACK LOW
IF YES, WE ARE NOT AT TOP
ELSE AT TOP: SET CARRY
RETURN
[COMMON TO GOSUB AND FOR]
#GFHEAD
: RCONT
#GFDISP
[TOPRSTK], Y
SVDISP
[TOPRSTK], Y
TSLNUM+1
GET LENGTH OF HEADER
TAKE IT OFF STACK
GET INDEX TO SAVED LINE
DISPL
GET SAVED LINE DISPL
SAVE
POINT TO LINE # IN HEADER
GET LINE # HIGH
SAVE LINE # HIGH
GET DISPL TO LINE # LOW
227
Source Code
B860
B862
B190
85A0
LDA
STA
[TOPRSTK], Y
TSLNUM
B864
B865
B867
88
B190
F007 "B870
DEY
LDA
BEQ
GET
[TOPRSTK], Y
:FND
12 BYTE FOR
B869
B86A
B86C
B86F
48
A90C
2072B8
68
PHA
LDA
JSR
PLA
#FBODY
: RCONT
B870
B870
B871
18
60
:FND
CLC
RTS
:RCONT — Contract Ru
i Stack
+
*
ON
ENTRY A -
B872
B872
B873
B875
A8
A290
4CFBA8
*
: RCONT
TAY
LDX
JMP
#TOPRSTK
CONTLOW
GET LINE # LOW
SAVE LINE # LOW
POINT TO TYPE
GET TYPE
IF TYPE = GOSUB,
SET ELEMENT
SAVE VAR #
GET # BYTES TO POP
POP FROM RUN STACK
GET VAR ♦
CLEAR CARRY [ENTRY POPPED]
# OF BYTES TO SUBTRACT
; Y=LENGTH
;X = PTR TO RUN STACK
:REXPAN — Expand Run Stack
* ON ENTRY A - # OF BYTES TO ADD
*
* ON EXIT ZTEMP1 - OLD TOPRSTK
B878
B878 2081B8
B87B A8
B87C A290
B87E 4C7FA8
: REXPAN
JSR : SAVRTOP
TAY
LDX #TOPRSTK
JMP EXPLOW
SAVE RUN STACK TOP
Y=LENGTH
X=PTR TO TOP RUN STACK
GO EXPAND
: SAVRTOP — Save
Top of Run Stack in ZTEMP1
B881
B881 A690
B883 86C4
B88S A691
B887 86C5
B889 60
: SAVRTOP
LDX TOPRSTK
STX TEMPA
LDX TOPRSTK+1
STX TEMPA+1
RTS
SAVE TOPRSTK
X
X
:SAVDEX — Save Line Displacement
B88A
B88A A4A8
B88C 84B3
B88E 60
: SAVDEX
LDY STINDEX
STY SAVDEX
RTS
GET STMT INDEX
SAVE IT
:MV6RS — Move 6-Byte Value to Run Stack
* ON ENTRY X - LOCATION TO MOVE FROM
* Y- DISPL FROM ZTEMP1 TO MOVE TO
* ZTEMP1 - LOCATION OF RUN STK ELEMENT
B88F
:MV6RS
B88F
A906
LDA
#6
GET # OF BYTES TO MOVE
B891
8SC6
STA
ZTEMP2
SAVE AS COUNTER
B893
:MV
B893
B500
LDA
0,X
GET A BYTE
B895
91C4
STA
[TEMPA], Y
PUT ON STACK
B897
E8
I NX
POINT TO NEXT BYTE
B898
C8
I NY
POINT TO NEXT LOCATION
B899
C6C6
DEC
ZTEMP2
DEC COUNTER
B89B
D0F6 "B893
BNE
:MV
IF NOT = DO AGAIN
B89D
60
RTS
228
Source Code
:PL6RS — Pull 6 Bytes from Run Stack to FR1
* ON ENTRY
Y = DISPL FROM TOPRSTK TO MOVE PROM
TOPRSTK - START OF ELEMENT
B89E
:PL6RS
B89E
A906
LDA
#6
B8A0
85C6
STA
ZTEMP2
B8A2
A2E0
LDX
#FR1
B8A4
:PL
B8A4
B190
LDA
[TOPRSTK], Y
B8A6
9500
STA
0,X
B8A8
E8
I NX
B8A9
C8
I NY
B8AA
C6C6
DEC
ZTEMP2
B8AC
D0F6 "B8A4 BNE
:PL
B8AE
60
RTS
RSTPTR — Reset Stack Pointers [STARP and RUNSTK]
B8AF
RSTPTR
B8AF
A58C
LDA
STARP
B8B1
858E
STA
RUNSTK
B8B3
8590
STA
MEMTOP
B8B5
850E
STA
APHM
B8B7
A58D
LDA
STARP+1
B8B9
858F
STA
RUNSTK+1
B8BB
8591
STA
MEMTOP+1
B8BD
850F
STA
APHM+1
B8BF
60
RTS
GET # OF BYTES TO MOVE
SAVE AS COUNTER
GET A BYTE
SAVE IN Z PAGE
INC TO NEXT LOCATION
INC TO NEXT BYTE
DEC COUNTER
IP NOT =0, DO AGAIN
GET BASE OF STR/ARRAY
SPACE LOW
RESET
SET APPLICATION HIMEM
GET BASE STR/ARRAY SPACE
HIGH
RESET
X
SET APPLICATION HIMEM
ZVAR — Zero Variable
B8C0 ZVAR
B8C0
A686
LDX
WTP
MOVE VARIABLE TABLE POINTER
B8C2
86F5
STX
ZTEMP1
X
B8C4
A487
LDY
WTP+1
X
B8C6
84F6
STY
ZTEMP1+1
ARE WE AT END OF TABI
X
B8C8
ZVAR1
B8C8
A6F6
LDX
ZTEMP1+1
GET NEXT VARIABLE ADDR HIGH
B8CA
E489
CPX
ENDWT+1
IS IT < END VALUE HIGH
B8CC
9007
"B8D5
BCC
:ZVAR2
IF YES, MORE TO DO
B8CE
A6F5
LDX
ZTEMP1
GET NEXT VARIABLE ADDR LOW
B8D0
E488
CPX
ENDWT
IS IT < END VALUE LOW
B8D2
9001
"B8D5
BCC
:ZVAR2
IP YES, MORE TO DO
B8D4
60
RTS
ZERO A VARIABLE
ELSE, DONE
B8D5
ZVAR2
B8D5
A000
LDY
#0
TURN OFF
B8D7
B1F5
LDA
[ZTEMP1], Y
DIM FLAG
B8D9
29FE
AND
#$FE
B8DB
91F5
STA
[ZTEMP1], Y
B8DD
A002
LDY
#2
INDEX PAST VARIABLE HEADER
B8DF
A206
LDX
#6
GET # OF BYTES TO ZERO
B8E1
A900
LDA
#0
CLEAR A
B8E3
ZVAR3
B8E3
91F5
STA
[ZTEMP1],Y
ZERO BYTE
B8E5
C8
I NY
POINT TO NEXT BYTE
B8E6
CA
DEX
DEC POINTER
B8E7
D0FA
"B8E3
BNE
:ZVAR3
IF NOT = 0, ZERO NEXT BYTE
229
Source Code
B8E9 A5F5
B8EB 18
B8EC 6908
B8EE 85P5
B8F0 A5F6
B8F2 6900
B8F4 85F6
B8F6 D0D0 "B8C8
LDA
ZTEMP1
; GET CURRENT VARIABLE
POINTER LOW
CLC
ADC
#8
I INCR TO NEXT VARIABLE
STA
ZTEMP1
; SAVE NEW VARIABLE POINTER
LOW
LDA
ZTEMP1+1
; GET CURRENT VARIABLE
POINTER HIGH
ADC
#0
; ADD IN CARRY
STA
ZTEMP1+1
; SAVE NEW VARIABLE POINTER
HIGH
BNE
:ZVAR1
; UNCONDITIONAL BRANCH
RUNINIT — Initialize Storage Locations for RUN
B8F8
RUNINIT
B8F8
A000
LDY
#0
CLEAR A
B8FA
84BA
STY
STOPLN
CLEAR LINE # STOPPED AT
B8FC
84BB
STY
STOPLN+1
X
B8FE
84B9
STY
ERRNUM
CLEAR ERROR #
B900
84FB
STY
RADFLG
CLEAR FLAG TOR TRANSENDENTALS
B902
84B6
STY
DATAD
CLEAR DATA POINTERS
B904
84B7
STY
DATALN
X
B906
84B8
STY
DATALN+1
X
B908
88
DEY
B909
84BD
STY
TRAPLN+1
SET TRAP FLAG TO NO TRAP
B90B
8411
STY
BRKBYT
SET BRK BYTE OFF [$FF]
B90D
4C41BD
JMP
CLSALL
GO CLOSE ALL DEVICES
TSTEND - Test for
End of Statem
ent
*
ON
EXIT CC
SET
*
CARRY
SET
- END OF STMT
*
CARRY
CLE)
VR - NOT END OF STMT
B910
TSTEND
B910
A6A8
LDX
STINDEX
B912
E8
I NX
B913
E4A7
CPX
NXTSTD
B915
60
RTS
Error Messages
Error Message Routine
B916
E6B9
ERRNSF
INC
ERRNUM
B918
E6B9
ERRDNO
INC
ERRNUM
B91A
E6B9
ERRPTL
INC
ERRNUM
B91C
E6B9
ERSVAL
INC
ERRNUM
B91E
E6B9
XERR
INC
ERRNUM
B920
E6B9
ERBRTN
INC
ERRNUM
B922
E6B9
ERGFDE
INC
ERRNUM
B924
E6B9
ERLTL
INC
ERRNUM
B926
E6B9
ERNOFOR
INC
ERRNUM
B928
E6B9
ERNOLN
INC
ERRNUM
B92A
E6B9
EROVFL
INC
ERRNUM
B92C
E6B9
ERRAOS
INC
ERRNUM
B92E
E6B9
ERRDIM
INC
ERRNUM
B930
E6B9
ERRINP
INC
ERRNUM
B932
E6B9
ERRLN
INC
ERRNUM
B934
E6B9
ERROOD
INC
ERRNUM
B936
E6B9
ERRSSL
INC
ERRNUM
B938
E6B9
ERRVSF
INC
ERRNUM
B93A
E6B9
ERVAL
INC
ERRNUM
B93C
E6B9
MEMFULL
INC
ERRNUM
B93E
E6B9
ERON
INC
ERRNUM
FILE NOT SAVE FILE
#DN0 > 7
LOAD PGM TOO BIG
STRING NOT VALID
EXECUTION OF GARBAGE
BAD RETURNS
GOSUB/FOR LINE DELETED
LINE TO LONG
NO MATCHING FOR
LINE NOT FOUND [GOSUB/GOTO]
FLOATING POINT OVERFLOW
ARG STACK OVERFLOW
ARRAY/STRING DIM ERROR
INPUT STMT ERROR
VALUE NOT <32768
READ OUT OF DATA
STRING LENGTH ERROR
VARIABLE TABLE FULL
VALUE ERROR
MEMORY FULL
NO LINE # FOR EXP IN ON
230
Source Code
Error Routine
B940
B940 A900
B942 8DFE02
B945 20A7B7
B948 A5BD
B94A 3015 "E
B94C 85A1
B94E
A5BC
B950
85A0
B952
A980
B954
85BD
B956
A5B9
B958
85C3
B95A
A900
B95C
85B9
B95E
4CAEB6
ERROR
LDA
#0
STA
DSPPLG
JSR
STOP
LDA
TRAPLN+1
BMI
:ERRM1
*
TRAP SET - GO TO
STA
TSLNUM+1
LDA
TRAPLN
STA
TSLNUM
LDA
#$80
STA
TRAPLN+1
LDA
ERRNUM
STA
ERRSAV
LDA
#0
STA
ERRNUM
JMP
XGOl
*
*
NO
TRAP - PRINT I
; FLAG
; SET LINE # STOPPED AT
; GET TRAP LINE # HIGH
| IF NO LINE # PRINT MESSAGE
SPECIFIED LINE #
; SET TRAP LINE # HIGH FOR
GET STMT
; GET TRAP LINE # LOW
; SET FOR GET STMT
; TURN OFF TRAP
GET ERROR #
SAVE IT
CLEAR
ERROR#
JOIN GOTO
B961
Print Error Message Part 1 [**ERR]
B961
206EBD
JSR
PRCR
B964
A937
LDA
#CERR
B966
203DB6
JSR
LSTMC
Print Error Number
B969
A5B9
LDA
ERRNUM
B96B
85D4
STA
FR0
B96D
A900
LDA
#0
B96F
85D5
STA
FR0+1
B971
209CB9
JSR
:PRINUM
B974
:ERRM2
B974
20E2A9
JSR
TENDST
B977
3019 ~B992
BMI
:ERRDONE
PRINT CR
GET TOKEN FOR ERROR
GO PRINT CODE
GET ERROR
SET ERROR
SET ERROR
X
# OF FR0 AS INTEGER
# HIGH
GO PRINT ERROR #
TEST FOR DIRECT STMT
IF DIRECT STMT, DONE
Print Message Part 2 [AT LINE]
B979
A9AE
B97B
8595
B97D
A9B9
B97F
8596
B981
2035B5
Print Line Number
B984
A001
B986
B18A
B988
85D5
B98A
88
B9SB
B18A
B98D
85D4
B98F 209CB9
LDA
#:ERRMS&255
STA
SRCADR
LDA
#:ERRMS/256
STA
SRCADR+1
JSR
LPRTOKEN
LDY
#1
LDA
[STMCUR], Y
STA
FR0+1
DEY
LDA
[STMCUR], Y
STA
FR0
JSR
: PRINUM
SET POINTER TO MSG FOR PRINT
X
X
X
SET DISPL
GET LINE # HIGH
SET IN FR0 FOR CONVERT
GET CURRENT LINE # LOW
GET UNUSED LINE # LOW
SET IN FR0 LOW FOR CONVERT
PRINT LINE #
231
Source Code
B992
:ERRDONE
B992
206EBD
JSR
PRCR
B995
A900
LDA
#0
B997
85B9
STA
ERRNUM
B999
4C60A0
JMP
SYNTAX
PRINT CR
CLEAR A
CLEAR ERROR #
Print Integer Number in FRO
B99C
:PRINUM
B99C
20AAD9
JSR
CVIFP
B99F
20E6D8
JSR
CVFASC
B9A2
A5F3
LDA
INBUFF
B9A4
8595
STA
SRCADR
B9A6
A5F4
LDA
INBUFF+1
B9A8
8596
STA
SRCADR+1
B9AA
2035B5
JSR
LPRTOKEN
B9AD
60
RTS
204154204C
494E45A0
ERRMS DC
CONVERT TO FLOATING POINT
CONVERT TO ASCII
GET ADR OF # LOW
SET FOR PRINT ROUTINE
GET ADR OF # HIGH
SET FOR PRINT ROUTINE
GO PRINT ERROR #
Execute Graphics Routines
XSETCOLOR-
-Execute SET COLOR
B9B7
XSETCOLOR
B9B7
20E9AB
JSR
GET1INT
; GET REGISTER #
B9BA
A5D4
LDA
FR0
; GET #
B9BC
C905
CMP
#5
; IS IT <5?
B9BE
B01A "B9DA
BCS
:ERCOL
; IF NOT, ERROR
B9C0
48
PHA
; SAVE
B9C1
20E0AB
JSR
GETINT
j GET VALUE
B9C4
A5D4
LDA
FR0
; GET VALUE* 16+6
B9C6
AS LA
T X
B9C6
+0A
ASL
A
B9C7
AS LA
; X
B9C7
+0A
ASL
A
B9C8
ASLA
; X
B9C8
+0A
ASL
A
B9C9
ASLA
r X
B9C9
+0A
ASL
A
B9CA
48
PHA
; SAVE ON STACKS
B9CB
20E0AB
JSR
GETINT
; GET VALUE 3
B9CE
68
PLA
; GET VALUE 2*16 FROM STACK
B9CF
18
CLC
B9D0
6 5D4
ADC
FR0
; ADD IN VALUE 3
B9D2
A8
TAY
; SAVE VALUE 2*16 + VALUE 5
B9D3
6 8
PLA
; GET INDEX
B9D4
AA
TAX
; PUT IN X
B9D5
98
TYA
; GET VALUE
B9D6
9DC402
STA
CREGS.X
;SET VALUE IN REGS
B9D9
60
RTS
B9DA
:ERSND
B9DA
:ERCOL
B9DA
203AB9
JSR
ERVAL
XSOUND — Execute SOUND
B9DD
XSOUND
B9DD
20E9AB
JSR
GET1INT
; GET 1 BYTE INTEGER
B9E0
A5D4
LDA
FR0
; X
B9E2
C904
CMP
#4
; IS IT <4?
B9E4
B0F4 "B9DA
BCS
:ERSND
; IF NOT, ERROR
232
Source Code
B9E6
B9E6 +0A
B9E7 48
B9E8 A900
B9EA 8D08D2
B9ED A903
B9EP 8D0FD2
B9F2
B9F5
B9F6
B9F7
B9F8
B9FA
20E0AB
68
48
AA
A5D4
9D00D2
B9FD
BA00
BA02
BA02 +0A
BA03
BA03 +0A
BA04
BA04 +0A
BA05
BA05 +0A
20E0AB
A5D4
BA07
BA0A
BA0B
BA0C
BA0D
BA0E
BA0F
BA10
BA12
BA15
20E0AB
68
A 8
68
AA
98
18
65D4
9D01D2
60
ASLA
ASL
A
PHA
LDA
#0
STA
SREG1
LDA
#3
STA
SKCTL
JSR
GETINT
PLA
PHA
TAX
LDA
FR0
STA
SREG2.X
JSR
GETINT
LDA
FR0
ASLA
ASL
A
ASLA
ASL
A
ASLA
ASL
A
ASLA
ASL
A
PHA
JSR
GETINT
PLA
TAY
PLA
TAX
TYA
CLC
ADC
FR0
STA
SREG3.X
RTS
| GET VALUE *2
SET TO ZERO
X
GET EXP2
GET INDEX
SAVE AGAIN
PUT IN INDEX REG
GET VALUE
SAVE IT
GET EXP 3
GET 16*EXP3
X
SAVE IT
GET EXP4
GET 16*EXP3
SAVE IT
GET INDEX
PUT IN X
GET EXP3*16
GET 16*EXP3+EXP4
STORE IT
XPOS — Execute POSITION
BA16
BA16
BA19
BA1B
BA1D
BA1F
20E0AB
A5D4
8555
A5D5
8556
BA21 20E9AB
BA24 A5D4
BA26 8554
BA28 60
BA29
BA29
BA2C
BA2E
BA30
20E0AB
A5D4
85C8
60
BA31
BA31 2016BA
BA34 A5C8
BA36 8DFB02
JSR
GETINT
LDA
FR0
STA
SCRX
LDA
FR0+1
STA
SCRX+1
JSR
GET1INT
LDA
FR0
STA
SCRY
RTS
COLOR
XCOLOR
JSR
GETINT
LDA
FR0
STA
COLOR
RTS
e DRAWTO
XDRAWTO
JSR
XPOS
LDA
COLOR
STA
SVCOLOR
GET INTEGER INTO FR0
SET X VALUE
X
X
X
SET Y VALUE
X
X
GET INTEGER INTO FR0
GET X,Y POSITION
GET COLOR
233
Source Code
BA39
A911
BA3B
A206
BA3D
20C4BA
BA40
A90C
BA42
9D4A03
BA45
A900
BA47
9D4B03
BA4A
2024BD
BA4D
4CB3BC
XCR-
- Execul
BA50
BA50
A206
BA52
86C1
BA54
20F1BC
BA57
20E0AB
BA5A
A27 3
BA5C
A0BA
BA5E
86F3
BA60
84F4
BA62
A206
BA64
A5D4
BA66
29F0
BA68
491C
BA6A
A8
BA6B
A5D4
BA6D
20D1BB
BA70
4CB3BC
LDA
tICDRAW
LDX
#6
JSR
GLPCX
LDA
#$0C
STA
ICAUX1.X
LDA
#0
STA
ICAUX2.X
JSR
107
JMP
IOTEST
LDX
#6
STX
IODVC
JSR
CLSYS1
JSR
GETINT
LDX
#SSTR&255
LDY
#SSTR/256
STX
INBUFF
STY
INBUFF+1
LDX
#6
LDA
FR0
AND
#?F0
EOR
#ICGR
TAY
LDA
FR0
JSR
SOPEN
JMP
IOTEST
GET COMMAND
SET DEVICE
SET THEM
SET AUX 1
SET AUX 2
GET DEVICE
SAVE DEVICE #
GO CLOSE IT
GET INTEGER INTO FR0
SET INBUFF TO POINT
TO FILE SPEC STRING
X
X
GET DEVICE #
SET SOME BITS FOR GRAPHICS
GET AUX2 [GRAPHICS TYPE]
OPEN
TEST I/O OK
BA73 533A9B
XPLOT — Execute PLOT
BA76
XPLOT
BA76
2016BA
JSR
XPOS
BA79
A5C8
LDA
COLOR
BA7B
A206
LDX
#6
BA7D
4CA1BA
JMP
PRCX
SET X,Y POSITION
GET COLOR
GET DEVICE #
GO PRINT IT
Input/Output Routines
LOCAL
GETLINE - Get a Line of Input
GLINE - GET LINE L PROMPT ONLYJ
GNLINE - GET NEW LINE [CR, PROMPT]
BA80
ONLINE
BA80
A6B4
LDX
ENTDTD
IF ENTER DEVICE NOT ZERO
BA82
D00E *
BA92
BNE
GLGO
THEN DO PROMPT
BA84
A99B
LDA
#CR
PUT EOL
BA86
209FBA
JSR
PUTCHAR
BA89
GLINE
BA89
A6B4
LDX
ENTDTD
IF ENTER DEVICE NOT ZERO
BA8B
D005 "
BA92
BNE
GLGO
THEN DON'T PROMPT
BA8D
A5C2
LDA
PROMPT
PUT PROMPT
BA8F
209FBA
JSR
PUTCHAR
BA92
GLGO
BA92
A6B4
LDX
ENTDTD
BA94
A905
LDA
tICGTR
234
Source Code
BA96
20C4BA
BA99
200ABD
BA9C
4CB3BC
PUTCHAR — P
BA9F
BA9F
BA9F
A6B5
BAA1
BAA1
48
BAA 2
20C6BA
BAA 5
BD4A0 3
BAA 8
852A
BAAA
BD4B03
BAAD
852B
BAAF
68
BAB0
A8
BAB1
20B8BA
BAB 4
98
BAB 5
4CB6BC
BAB 8
BAB 8
BD4703
BABB
48
BABC
BD4603
BABF
48
BAC0
98
BAC1
A092
BAC3
60
BAC4
85C0
BAC6
BAC6
86C1
BAC8
4CA6BC
JSR
GLPCX
JSR
101
JMP
I0TEST
Put One Character to List Device
PRCHAR
PUTCHAR
LDX LISTDTD
PRCX
PHA
JSR
GLPX
GO DO I/O
GO TEST RESULT
GET LIST DEVICE
SAVE 10 BYTE
SET DEVICE
LDA
STA
LDA
STA
PLA
TAY
JSR
ICAUX1.X r SET UP ZERO PAGE IOCB
ICAUX1-I0CB+ZICB ; X
ICAUX2.X ; X
ICAUX2-IOCB+ZICB ; X
:PDUM
RETURN HERE FROM ROUTINE
TYA ; TEST STATUS
JMP I0TES2
:PDUM
LDA
ICPUT+l.X
PHA
LDA
ICPUT.X
PHA
TYA
LDY
#?92
RTS
GLPCX
STA
IOCMD
GLPX
STX
IODVC
JMP
LDDVX
GO TO PUT ROUTINE
X
X
X
X
LOAD VALUE FOR CIO ROUTINE
AS I/O DEVICE
LOAD DEVICE X
XENTER — Execute ENTER
BACB
XENTER
BACB
A904
LDA
#$04
OPEN INPUT
BACD
20DDBA
JSR
ELADVC
• GO OPEN ALT DEVICE
BAD0
85B4
STA
ENTDTD
SET ENTER DEVICE
BAD2
4C60A0
JMP
SYNTAX
FLIST
— Open
LIST File
BAD5
FLIST
BAD5
A908
LDA
#$08
OPEN OUTPUT
BAD7
20DDBA
JSR
ELADVC
GO OPEN ALT DEVICE
BADA
85B5
STA
LISTDTD
SET LIST DEVICE
BADC
60
RTS
DONE
BADD
ELADVC
BADD
48
PHA
BADE
A007
LDY
#7
USE DEVICE 7
BAE0
84C1
STY
IODVC
SET DEVICE
BAE2
20A6BC
JSR
LDDVX
BEFORE
BAE5
A90C
LDA
tICCLOSE
GO CLOSE DEVICE
BAE7
2026BD
JSR
108
OPEN OF NEW ONE
BAEA
A003
LDY
#ICOI0
CMD IS OPEN
BAEC
84C0
STY
IOCMD
BAEE
68
PLA
BAEF
A000
LDY
#0
GET AUX2
BAF1
20FBBB
JSR
X0P2
GO OPEN
235
Source Code
BAP 4
BAF6
A907
60
LDA
RTS
#7
RUN from File
BAF7
BAF9
A9FF
D002
FRUN LDA
BNE
#$FF
XLOAD — Execute LOAD Command
BAFB
XLOAD
BAFB
A900
LDA
#0
BAFD
48
:LD0 PHA
BAFE
A904
LDA
#04 ';
BB00
20DDBA
JSR
ELADVC
BB03
68
PLA
BB04
XLOAD1
BB04
48
PHA
BB05
A907
LDA
#ICGTC ;
BB07
85C0
STA
IOCMD
BB09
85CA
STA
LOADFLG r
BB0B
20A6BC
JSR
LDDVX ;
BB0E
A00E
LDY
#ENDSTAR-OUTBUFF
BB10
2010BD
JSR
103
BB13
20B3BC
JSR
IOTEST
BB16
AD8005
LDA
MISCRAM+OUTBUFF ;
BB19
0D8105
ORA
MlSCRAM+OUTBUFF+1
BB1C
D038 ~BB56
BNE
: LDFER
BB1E
A28C
LDX
#STARP ;
BB20
18
:LD1 CLC
BB21
A580
LDA
OUTBUFF
BB23
7D0005
ADC
MISCRAM.X ;
BB26
A8
TAY
BB27
A581
LDA
OUTBUFF+1
BB29
7D0105
ADC
MISCRAM+l.X
BB2C
CDE602
CMP
HIMEM+1 ;
BB2F
900A "BB3B
BCC
:LD3 ;
BB31
D005 "BB38
BNE
:LD2 ;
BB33
CCE502
CPY
HIMEM
BB36
9003 "BB3B
BCC
:LD3
BB38
4C1AB9
:LD2 JMP
ERRPTL
BB3B
9501
:LD3 STA
1,X
BB3D
9400
STY
0,X
BB3F
CA
DEX
BB40
CA
DEX
BB41
E082
CPX
#VNTP ;
BB43
B0DB "BB20
BCS
: LD1 ,•
BB45
2088BB
JSR
:LSBLK ;
BB48
2066B7
JSR
XCLR i
BB4B
A900
LDA
#0 !
BB4D
85CA
STA
LOADFLG ;
BB4F
68
PLA
BB50
F001 "BB53
BEQ
:LD4 i
BB52
60
RTS
BB53
:LD4
BB53
4C50A0
JMP
SNX1 ;
BB56
: LDFER
BB56
A900
LDA
#0
BB58
85CA
STA
LOADFLG
BB5A
2016B9
JSR
ERRNSF
LOAD DEVICE
AND RETURN
SET RUN MODE
SET LOAD MODE
SAVE R/L TYPE
GO OPEN FOR INPUT
THE SPECIFIED DEVICE
GET R/L TYPE
SAVE R/L TYPE
CMD IS GET TEXT CHARS
SET LOAD IN PROGRESS
LOAD DEVICE X REG
r Y=REC LENGTH
GO GET TABLE BLOCK
TEST I/O
IF FIRST 2
r BYTES NOT ZERO
THEN NOT SAVE FILE
START AT STARP DISPL
; ADD LOMEM TO
LOAD TABLE DISPL
IF NEW VALUE NOT
LESS THEN HIMEM
THEN ERROR
ELSE SET NEW TABLE VALUE
DECREMENT TO PREVIOUS TBL
ENTRY
IF NOT AT LOWER ENTRY
THEN CONTINUE
LOAD USER AREA
EXECUTE CLEAR
RESET LOAD IN PROGRESS
X
LOAD R/S STATUS
BR IF LOAD
RETURN TO RUN
GO TO SYNTAX
RESET LOAD IN PROGRESS
NOT SAVE FILE
236
Source Code
XSAVE — Execute SAVE Command
BB5D
XSAVE
BB5D
A908
LDA
#08
BB5F
20DDBA
JSR
ELADVC
BB62
XSAVE 1
BB62
A90B
LDA
fICPTC
BB64
85C0
STA
IOCMD
BB66
A280
LDX
#OUTBUFF
BB68
38
:SV1 SEC
BB69
B500
LDA
0,X
BB6B
E580
SBC
OUT BUFF
BB6D
9D0005
STA
MISCRAM,X
BB70
E8
INX
BB71
B500
LDA
0,X
BB73
E581
SBC
OUTBUFF+1
BB75
9D0005
STA
MISCRAM.X
BB78
E8
INX
BB79
E08E
CPX
#ENDSTAR
BB7B
90EB "BB68
BCC
iSVl
BB7D
20A6BC
JSR
LDDVX
BB80
A00E
LDY
#ENDSTAR-OUTBUFF
BB82
2010BD
JSR
103
BB85
20B3BC
JSR
IOTEST
LSBLK
— LOAD or
SAVE User Area
as a Block
BB88
:LSBLK
BB88
20A6BC
JSR
LDDVX
BB8B
A582
LDA
VNTP
BB8D
85F3
STA
INBUFF
BB8F
A583
LDA
VNTP+1
BB91
85F4
STA
INBUFF+1
BB93
AC8D05
LDY
MISCRAM+STARP+1
BB96
88
DEY
BB97
98
TYA
BB98
AC8C05
LDY
MISCRAM+STARP
BB9B
2012BD
JSR
104
BB9E
20B3BC
JSR
IOTEST
BBA1
4CF1BC
JMP
CLSYS1
GO OPEN FOR OUTPUT
THE SPECIFIED DEVICE
I/O CMD IS PUT TEXT CHARS
SET I/O CMD
MOVE RAM TABLE PTRS
[OUTBUFF THRU ENSTAR]
TO LBUFF
AS DISPLACEMENT
FROM LOW MEM
OUTPUT LBUFF
; FOR PROPER LENGTH
TEST GOOD I/O
LOAD DEVICE X REG
SET VAR NAME TBL PTR
AS START OF BLOCK ADR
; A,Y = BLOCK LENGTH
; GO DO BLOCK I/O
;G0 CLOSE DEVICE
XCSAVE — Execute CSAVE
BBA4
BBA4 A908
BBA6 20B6BB
XCSAVE
LDA
JSR
#8
COPEN
GET OPEN FOR OUTPUT
OPEN CASSETTE
BBA9 4C62BB JMP
XCLOAD — Execute CLOAD
BBAC
A904
LDA
#4
BBAE
20B6BB
JSR
COPEN
BBB1
A900
LDA
#0
BBB3
4C04BB
JMP
XL0AD1
GET OPEN FOR OUTPUT
OPEN CASSETTE
GET LOAD TYPE
DO LOAD
COPEN — OPEN Cassette
*
ON ENTRY: A -
*
*
ON EXIT: A -
BBB6
COPEN
BBB6
48
PHA
BBB7
A2CE
LDX
#:CSTR6,255
BBB9
86F3
STX
INBUFF
TYPE OF OPEN [IN OR OUT]
DEVICE #7
237
Source Code
BBBB
A2BB
LDX
#:CSTR/256
BBBD
86F4
STX
INBUFF+1
BBBF
A207
LDX
#7
BBC1
68
PLA
BBC2
A8
TAY
; SET COMMAND TYPE
BBC3
A980
LDA
#$80
; GET AUX 2
BBC 5
20D1BB
JSR
SOPEN
; GO OPEN
BBC8
20B3BC
JSR
IOTEST
BBCB
A907
LDA
#7
; GET DEVICE
BBCD
60
RTS
BBCE 433A9B
SOPEN — OPEN System Device
ON ENTRY X - DEVICE
Y - AUX1
A - AUX2
INBUFF - POINTS TO FILE SPEC
BBD1
SOPEN
BBD1
48
PHA
SAVE AUX2
BBD2
A903
LDA
IICOIO
GET COMMAND
BBD4
20C4BA
JSR
GLPCX
GET DEVICE/COMMAND
BBD7
68
PLA
SET AUX2 & AUX 1
BBD8
9D4B03
STA
ICAUX2.X
X
BBDB
98
TYA
BBDC
9D4A03
STA
ICAUX1,X
BBDF
2019BD
JSR
105
DO COMMAND
BBE2
4C51DA
JMP
INTLBF
RESET INBUFF
XXIO — Execute XIO Statement
XXIO
BBE5
BBE5 2004BD
BBE8 4CEDBB
JSR GIOCMD
JMP X0P1
XOPEN — Execute OPEN Statement
GET THE COMMAND BYTE
CONTINUE AS IF OPEN
BBEB
XOPEN
BBEB
A903
LDA
#IC0IO
; LOAD OPEN CODE
BBED
85C0
X0P1 STA
IOCMD
BBEF
209FBC
JSR
GIODVC
; GET DEVICE
BBF2
2004BD
JSR
GIOCMD
; GET AUX1
BBF5
48
PHA
BBF6
2004BD
JSR
GIOCMD
,- GET AUX2
BBF9
A8
TAY
; AUX2 IN Y
BBFA
68
PLA
; AUX1 IN A
BBFB
X0P2
BBFB
48
PHA
; SAVE AUX1
BBFC
98
TYA
BBFD
48
PHA
; SAVE AUX2
BBFE
20E0AA
JSR
EXEXPR
; GET FS STRING
BC01
2079BD
JSR
SETSEOL
; GIVE STRING AN EOL
BC04
20A6BC
JSR
LDDVX
; LOAD DEVICE X REG
BC07
68
PLA
BC08
9D4B03
STA
ICAUX2,X
; SET AUX 2
BC0B
68
PLA
; GET AUX 1
BC0C
9D4A03
STA
ICAUX1.X
BC0F
200ABD
JSR
101
r GO DO I/O
BCI2
2099BD
JSR
RSTSEOL
; RESTORE STRING EOL
238
Source Code
BC15
2051DA
JSR
INTLBF
BC18
4CB3BC
JMP
IOTEST
GO TEST I/O STATU
XCLOSE — Execute CLOSE
BC1B
XCLOSE
BC1B
A90C
LDA
#ICCLOSE
CLOSE CMD
GDVCIO — General Device I/O
BC1D
GDVCIO
BC1D
85C0
STA
IOCMD
SET CMD
BC1F
209FBC
JSR
GIODVC
GET DEVICE
BC22
2024BD
GDI01 JSR
107
GO DO I/O
BC25
4CB3BC
JMP
IOTEST
GO TEST STATUS
XSTATUS — Execute STATUS
BC28
XSTATUS
BC28
209FBC
JSR
GIODVC
GET DEVICE
BC2B
A90D
LDA
KICSTAT
STATUS CMD
BC2D
2026BD
JSR
108
GO GET STATUS
BC30
20FBBC
JSR
LDIOSTA
LOAD STATUS
BC33
4C2DBD
JMP
ISVAR1
GO SET VAR
XNOTE — Execute NOTE
BC36
XNOTE
BC36
A926
LDA
#$26
NOTE CMD
BC38
201DBC
JSR
GDVCIO
GO DO
BC3B
BD4C03
LDA
ICAUX3,X
GET SECTOR St/. LO
BC3E
BC4D03
LDY
ICAUX4,X
AND HI
BC41
202FBD
JSR
ISVAR
GO SET VAR
BC44
20A6BC
JSR
LDDVX
GET DEVICE X REG
BC47
BD4E03
LDA
ICAUX5.X
GET DATA LENGTH
BC4A
4C2DBD
JMP
ISVAR1
GO SET VAR
XPOINT — Execute POINT
BC4D
XPOINT
BC4D
209FBC
JSR
GIODVC
GET I/O DEVICE NO
BC50
20D5AB
JSR
GETPINT
GET SECTOR NO.
BC53
20A6BC
JSR
LDDVX
GET DEVICE X
BC56
A5D4
LDA
FR0
SET SECTOR NO.
BC58
9D4C03
STA
ICAUX3,X
BC5B
A5D5
LDA
FR0+1
BC5D
9D4D03
STA
ICAUX4.X
BC60
20D5AB
JSR
GETPINT
GET DATA LENGTH
BC63
20A6BC
JSR
LDDVX
LOAD DEVICE X
BC66
A5D4
LDA
FR0
GET AL
BC68
9D4E03
STA
ICAUX5.X
SET DATA LENGTH
BC6B
A925
LDA
#525
SET POINT CMD
BC6D
85C0
STA
IOCMD
BC6F
4C22BC
JMP
GDI01
GO DO
XPUT
— Execute PUT
BC72
XPUT
BC72
209FBC
JSR
GIODVC
GET DEVICE #
BC75
20E0AB
JSR
GET I NT
GET DATA
BC78
A5D4
LDA
FR0
X
BC7A
A6C1
LDX
IODVC
LOAD DEVICE #
BC7C
4CA1BA
JMP
PRCX
GO PRINT
XGET
— Execute GET
BC7F
XGET
BC7F
209FBC
JSR
GIODVC
GET DEVICE
BC82
GET1
BC82
A907
LDA
#ICGTC
GET COMMAND
BC84
85C0
STA
IOCMD
SET COMMAND
239
Source Code
BC86
A001
LDY
#1
SET BUFF LENGTH=1
BC88
2010BD
JSR
103
DO 10
BC8B
20B3BC
JSR
IOTEST
TEST I/O
BC8E
A000
LDY
#0
GET CHAR
BC90
B1F3
LDA
[INBUFF], Y
X
BC92
4C2DBD
JMP
ISVAR1
ASSIGN VAR
XLOCATE - Execute LOCATE
BC95
XLOCATE
BC95
2016BA
JSR
XPOS
GET X,Y POSITION
BC98
A206
LDX
#6
GET DEVICE #
BC9A
20C6BA
JSR
GLPX
X
BC9D D0E3 "BC82
GET!
GIODVC — Get I/O Device Number
BC9F
BC9F 2002BD
BCA2 85C1
BCA4 P00A "BCB0
GIODVC
JSR GIOPRM
STA IODVC
BEQ DNERR
GET PARM
SET AS DEVICE
BR IF DVC=0
LDDVX — Load X Register with I/O Device Offset
BCA6
BCA6
A5C1
LDA
IODVC
GET DEVICE
BCA8
ASLA
MULT BY 16
BCA8
+0A
ASL
A
BCA9
ASLA
BCA9
+0A
ASL
A
BCAA
ASLA
BCAA
+0A
ASL
A
BCAB
ASLA
BCAB
+0A
ASL
A
BCAC
AA
TAX
PUT INTO X
BCAD
3001 "BCB0
BMI
DNERR
BR DN0>7
BCAF
60
RTS
AND RETURN
BCB0
2018B9
DNERR
JSR
ERRDNO
IOTEST - Test I/O Status
BCB3
IOTEST
BCB3
20FBBC
JSR
LDIOSTA
LOAD I/O STATUS
BCB6
I0TES2
BCB6
3001 "BCB9
BMI
SICKIO
BR IF BAD
BCB8
60
RTS
ELSE RETURN
BCB9
SICKIO
BCB9
A000
LDY
#0
RESET DISPLAY FLAG
BCBB
8CFE02
STY
DSPFLG
BCBE
C980
CMP
#ICSBRK
IF BREAK
BCC0
D00A "BCCC
BNE
:SI01
SIMULATE ASYNC
BCC2
8411
STY
BRKBYT
BREAK
BCC4
A5CA
LDA
LOADFLG
IF LOAD FLAG SET
BCC6
F003 "BCCB
BEQ
:SIOS
BCC8
4C00A0
JMP
COLDSTART
DO COLDSTART
BCCB
:SI0S
BCCB
60
RTS
BCCC
A4C1
:SI01
LDY
IODVC
PRE-LOAD I/O DEVICE
BCCE
C988
CMP
#$88
WAS ERROR EOF
BCD0
F00F "BCE1
BEQ
:SI04
BR IF EOF
BCD2
85B9
:SI02
STA
ERRNUM
SET ERROR NUMBER
BCD4
C007
CPY
#7
WAS THIS DEVICE #7
BCD6
D003 "BCDB
BNE
:SI03
BR IF NOT
BCD8
20F1BC
JSR
CLSYSD
CLOSE DEVICE 7
BCDB
2072BD
:SI03
JSR
SETDZ
SET L/D DEVICE =
BCDE
4C40B9
JMP
ERROR
REPORT ERROR
240
Source Code
BCEl
C007
:SI04
CPY
#7
WAS EOF ON DEVICE 7
BCE3
D0ED "BCD2
BNE
:SI02
BR IF NOT
BCE5
A25D
LDX
#EPCHAR
WERE WE IN ENTER
BCE7
E4C2
CPX
PROMPT
BCE9
D0E7 *BCD2
BNE
:SI02
BR NOT ENTER
BCEB
20F1BC
JSR
CLSYSD
CLOSE DEVICE 7
BCEE
4C53A0
JMP
SNX2
GO TO SYNTAX
CLSYSD — Close System Device
BCFl CLSYSD
BCF1
20A6BC
CLSYS1
JSR
LDDVX
BCF4
F00B ~BD01
BEQ
NOCD0
• DON'T CLOSE DEVICE0
BCF6
A90C
LDA
#ICCLOSE
■ LOAD CLOSE CORD
BCF8
4C26BD
JMP
108
GO CLOSE
LDIOSTA — Load I/O Status
BCFB
LDIOSTA
BCFB
20A6BC
JSR
LDDVX
■ GET DEVICE X REG
BCFE
BD4303
LDA
ICSTA, X
GET STATUS
BD01
NOCD0
BD01
60
RTS
■ RETURN
GIOPRM — Get I/O Parameters
BD02
GIOPRM
BD02
E6A8
INC
STINDEX
SKIP OVER #
BD04
20D5AB
GIOCMD
JSR
GETPINT
GET POSITIVE INT
BD07
A5D4
LDA
FR0
MOVE LOW BYTE TO
BD09
60
RTS
I/O Call Routine
BD0A
A0FF
101
LDY
#255
BUFL » 255
BD0C
D002 "BD10
BNE
103
BD0E
A000
102
LDY
#0
BUFL =
BD10
A900
103
LDA
#0
BUFL < 256
BD12
9D4903
104
STA
ICBLH.X
SET BUFL
BD15
98
TYA
BD16
9D4803
STA
ICBLL,X
BD19
A5F4
105
LDA
INBUFF+1
LOAD INBUFF VALUE
BD1B
A4F3
LDY
INBUFF
BD1D
BD20
9D4503
98
106
TYA
STA
ICBAH, X
SE BUF ADR
BD21
9D4403
STA
ICBAL.X
BD24
A5C0
107
LDA
IOCMD
LOAD COMMAND
BD26
9D4203
108
STA
ICCOM.X
SET COMMAND
BD29
2056E4
JSR
CIO
GO DO I/O
BD2C
60
RTS
DONE
ISVAR
— I/O Variabl
eSet
BD2D
ISVARl
BD2D
A000
LDY
#0
GET HIGH ORDER BYTE
BD2F
ISVAR
BD2F
48
PHA
PUSH INT VALUE LOW
BD30
98
TYA
BD31
48
PHA
PUSH INT VALUE HI
BD32
200FAC
JSR
P0P1
GET VARIABLE
BD35
68
PLA
BD36
85D5
STA
FR0+1
SET VALUE LOW
BD38
68
PLA
BD39
85D4
STA
FR0
SET VALUE HI
BD3B
20AAD9
JSR
CVIFP
CONVERT TO FP
BD3E
4CI6AC
JMP
RTNVAR
AND RETURN TO TABLE
241
Source Code
CLSALL — CLOSE All lOCBs [except 0]
BD41 CLSALL
; TURN OFF
SOUND
BD41
A900
LDA
in
BD43
A207
LDX
#7
BD45
:CL
BD45
9D00D2
STA
SREG3-1.X
BD48
CA
DEX
BD49
D0FA "BD45
BNE
:CL
BD4B
A007
LDY
#7
; START AT DEVICE 7
BD4D
84C1
STY
IODVC
BD4F
20F1BC
CLALL1
JSR
CLSYSD
; CLOSE DEVICE
BD52
C6C1
DEC
IODVC
; DEC DEVICE #
BD54
D0F9 "BD4F
BNE
CLALL1
; BR IF NOT ZERO
BD56
60
RTS
PREADY — Print READY Message
BD57
PREADY
BD57
A206
LDX
tRML-1
; GET READY MSG LENGTH-1
BD59
86F2
PRDY1
STX
CIX
; SET LEN REM
BD5B
BD67BD
LDA
RMSG, X
; GET CHAR
BD5E
209FBA
JSR
PRCHAR
; PRINT IT
BD61
A6F2
LDX
CIX
; GET LENGTH
BD63
CA
DEX
BD64
10F3 "BD59
BPL
PRDY1
; BR IF MORE
BD66
60
RTS
BD67
9B59444145
529B
RMSG
DB
CR, 'YDAER'
,CR
= 0007
RML
EQU
*-RMSG
PRCR
— Print Carriage Return
BD6E
A200
PRCR
LDX
#0
; SET FOR LAST CHAR
BD70
F0E7 ~BD59
BEQ
PRDY1
; AND GO DO IT
SETDZ — Set Device as LIST/ENTER Device
BD72 A900
BD74 85B4
BD76 85B5
BD78 60
SETDZ LDA #0
STA ENTDTD
STA LISTDTD
RTS
SETSEOL — Set an EOL [Temporarily] after a String EOL
BD79
SETSEOL
BD79
2098AB
JSR
AAPSTR
; GET STRING WITH ABS ADR
BD7C
A5D4
LDA
FR0-2+EVSADR
; PUT IT'S ADR
BD7E
85F3
STA
INBUFF
; INTO INBUFF
BD80
A5D5
LDA
FR0-1+EVSADR
BD82
85F4
STA
INBUFF+1
BD84
A4D6
LDY
FR0-2+EVSLEN
; GET LENGTH LOW
BD86
A6D7
LDX
FR0-1+EVSLEN
; IF LEN < 256
BD88
F002 "BD8C
BEQ
:SSE1
; THEN BR
BD8A
A0FF
LDY
»$FF
; ELSE SET MAX
BD8C
BIF3
:SSE1 LDA
[INBUFF], Y
; GET LAST STR CHAR+1
BD8E
8597
STA
INDEX2
; SAVE IT
BD90
8498
STY
INDEX2+1
; AND IT ' S INDEX
BD92
A99B
LDA
#CR
; THEN REPLACE WITH EOL
BD94
91F3
STA
[INBUFF], Y
BD96
8592
STA
MEOLFLG
; INDICATE MODIFIED EOL
BD98
60
RTS
; DONE
BD99
RSTSEOL
; RESTORE STRING CHAR
BD99
A49S
LDY
INDEX2+1
; LOAD INDEX
242
Source Code
BD9B
A597
LDA
INDEX2
LOAD CHAR
BD9D
91F3
STA
[INBUFF],Y
DONE
BD9F
A900
LDA
#0
BDA1
8592
STA
MEOLFLG
RESET EOL FLAG
BDA3
60
RTS
DONE
BDA4
= 0001
PATCH
DS
PATSIZ
SIN[X]andCOS[X]
BDA5
38
SINERR
SEC
TERROR - SET
BDA6
60
RTS
BDA7
A904
SIN
LDA
#4 ;
BDA9
24D4
BIT
FR0
BDAB
1006 "
BDB3
BPL
BOTH
BDAD
A902
LDA
#2 ;
BDAF
D002 "
BDB3
BNE
BOTH
BDB1
A901
COS
LDA
#1 ;
BDB3
85F0
BOTH
STA
SGNFLG
BDB5
A5D4
LDA
FR0
BDB7
297F
AND
#S7F
BDB9
85D4
STA
FR0
BDBB
A95F
LDA
#PIOV2&$FF
BDBD
18
CLC
BDBE
65FB
ADC
DEGFLG
BDC0
AA
TAX
BDC1
A0BE
LDY
#PIOV2/$100
BDC3
2098DD
JSR
FLD1R
BDC6
2028DB
JSR
FDIV ;
BDC9
9001 "
BDCC
BCC
SINF7
BDCB
60
S I NOVF
RTS
BDCC
SINF7
BDCC
A5D4
LDA
FR0
BDCE
297F
AND
#$7F f
BDD0
38
SEC
BDD1
E940
SBC
#$40
BDD3
302B "
BE00
BMI
SINF3 ;
BDD5
C904
SINF6
CMP
#FPREC-2
BDD7
10CC "
BDA5
BPL
SINERR ;
BDD9
AA
TAX
BDDA
B5D5
LDA
FR0+1.X ;
BDDC
85F1
STA
XFMFLG
BDDE
2910
AND
#510 7
BDE0
F002 *
BDE4
BEQ
SINF5
BDE2
A902
LDA
#2 ;
BDE4
18
SINF5
CLC
BDE5
65F1
ADC
XFMFLG
BDE7
2903
AND
#3
BDE9
65F0
ADC
SGNFLG ;
BDEB
85F0
STA
SGNFLG
BDED
86F1
STX
XFMFLG ;
BDEF
20B6DD
JSR
FMOVE
BDF2
A6F1
LDX
XFMFLG
BDF4
A900
LDA
#0
BDF6
95E2
SINF1
STA
FR1+2.X ;
BDF8
E8
I NX
BDF9
E003
CPX
#FPREC-3
BDFB
90F9 *
BDF6
BCC
SINF1
BDFD
2060DA
JSR
FSUB
BE00
46F0
SINF3
LSR
SGNFLG ;
BE02
900D "
BE11
BCC
SINF4 ;
BE04
20B6DD
JSR
FMOVE ;
BE07
A271
LDX
#FPONE&$FF
BE09
A0BE
LDY
#FPONE/$100
BE0B
2089DD
JSR
FLD0R
BE0E
2060DA
JSR
FSUB
BE11
SINF4
BE11
A2E6
LDX
#FPSCR&$FF
BE13
A005
LDY
#FPSCR/$100
FLAG SIN[X] ENTRY RIGHT NOW
SIN[-X]
FLAG COS[X] ENTRY
FORCE POSITIVE
X/CPI/2] OR X/90
OVERFLOW
CHECK EXPONENT
QUADRANT - USE AS IS
FIND QUAD NO & REMAINDER
OUT OF RANGE
X->LSB OR FR0
LSB
CHECK 10 'S DIGIT
ODD - ADD 2 TO QUAD #
QUADRANT = 0,1,2,3
ADJUST FOR SINE VS COSINE
SAVE DEC PT LOC
COPY TO FR1
CLEAR FRACTION
LEAVE REMAINDER
WAS QUAD ODD
NO
YES - USE 1.0 - REMAINDER
NOW DO THE SERIES THING
SAVE ARG
243
Source Code
BE15
BE18
BE1B
BE1E
BE 20
BE22
BE 24
BE26
BE29
BE2B
BE2D
BE30
BE33
BE35
BE37
BE38
BE3A
BE3C
BE3E
BE40
BE41
BE47
BE4D
BE53
BE59
BE5F
BE65
BE6B
BE71
20A7DD
20B6DD
20DBDA
B085 "BDA5
A906
A241
A0BE
2040DD
A2E6
A005
2098DD
20DBDA
46F0
9009 "BE40
18
A5D4
F004 ~BE40
4980
85D4
60
BD03551499
39
3E01604427
52
BE46817543
55
3F07969262
39
BF64596408
67
4001570796
32
= 0006
4090000000
00
3F01745329
25
4001000000
00
JSR
JSR
JSR
BCS
LDA
LDX
LDY
JSR
LDX
LDY
JSR
JSR
LSR
BCC
CLC
LDA
BEQ
EOR
STA
SINDON RTS
FST0R
FMOVE
FMUL
SINERR
#NSCF
#SCOEF&$FF
#SCOEF/$100
PLYEVL
#FPSCRS,$FF
#FPSCR/$100
FLD1R
FMUL
SGNFLG
SINDON
FR0
SINDON
#$80
FR0
;X->FR1
;X**2->FR0
EVALUATE P[X**2]
X-> FR1
SIN[X] = X*P[X**2]
WAS QUAD 2 OR 3?
NO - THRU
YES
FLIP SIGN
[UNLESS ZERO]
; RETURN
SCOEF .BYTE $BD, $03 , $55 , $14 , $99, $39 ; -.00000354149939
.BYTE S3E, $01, $60, $44, $27, $52 ; 0.000160442752
.BYTE $BE, $46, $81, $75, $43, $55 ; -.004681754355
.BYTE $3F, $07, $96, $92, $62, $39 ; 0.0796926239
.BYTE $BF, $64, $59, $64, $08, $67 ; -.6459640867
PIOV2 .BYTE $40, $01, $57, $07, $96, $32 ;Pl/2
NSCF EQU (*-SCOEF)/FPREC
.BYTE $40, $90, 0,0, 0,0 ; 90 DEG
PIOV18 .BYTE $3F, $01, $74, $53, $29, $25 ;Pl/180
FPONE .BYTE $40,1,0,0,0,0 ; 1.0
ATAN[X] — Arctangent
BE77
BE79
BE7B
BE7D
BE7F
BE81
BE83
BE85
BE87
BE89
BE8B
BE8D
BE8F
BE91
BE93
BE95
BE97
BE 9 A
BE 9 A
BE9C
BE9E
BEA1
BE A 4
BEA7
BEA9
BEAB
A900
85F0
85F1
A5D4
297F
C940
3015 "BE9A
A5D4
2980
85F0
E6F1
A97F
25D4
85D4
A2EA
A0DF
2095DE
A2E6
A005
20A7DD
20B6DD
20DBDA
B039 "BEE2
A90B
A2AE
BEAD A0DF
ATAN
STA
STA
LDA
AND
CMP
BMI
LDA
AND
STA
INC
LDA
AND
STA
LDX
LDY
JSR
ATAN1
LDX
LDY
JSR
JSR
JSR
BCS
LDA
LDX
LDY
#0
SGNFLG
XFMFLG
FR0
#$7F
#$40
ATAN1
FR0
#$80
SGNFLG
XFMFLG
#$7F
FR0
FR0
#FP9S&$FF
#FP9S/$100
XFORM
#FPSCR&$FF
#FPSCR/$100
FST0R
FMOVE
FMUL
ATNOUT
#NATCF
#ATCOEF&$FF
#ATCOEF/$100
ARCTAN[X]
SIGN FLAG OFF
5. TRANSFORM FLAG
CHECK X VS 1.0
X<1.0 - USE SERIES DIRECTLY
X> = 1.0 - SAVE SIGN S. TRANSFORM
REMEMBER SIGN
FORCE PLUS
; CHANGE ARG TO [X-1]/[X+1]
; ARCTAN[X], -1<X<1 BY SERIES
; OF APPROXIMATIONS
;X->FSCR
; X->FR1
; X*X->FR0
; ' FLOW
244
Source Code
BEAF
2040DD
JSR
PLYEVL
P[X*X]
BEB2
B02E "BEE2
BCS
ATNOUT
BEB4
A2E6
LDX
#FPSCRS,?FF
BEB6
A005
LDY
#FPSCR/?100
BEB8
2098DD
JSR
FLD1R
X->FR1
BEBB
20DBDA
JSR
FMUL
X*P[X*X]
BEBE
B022 "BEE2
BCS
ATNOUT
' FLOW
BEC0
A5F1
LDA
XFMFLG
WAS ARG XFORM'D
BEC2
F010 "BED4
BEQ
ATAN2
NO
BEC4
A2F0
LDX
#PIOV4&5FF
YES-ADD ARCTAN [1.0]
BEC6
A0DF
LDY
#PIOV4/5100
BEC8
2098DD
JSR
FLD1R
BECB
2066DA
JSR
FADD
BECE
A5F0
LDA
SGNFLG
GET ORG SIGN
BED0
05D4
ORA
FR0
BED2
85D4
STA
FR0
ATAN[-X] = - ATAN[X]
BED4
A5FB
ATAN2 LDA
DEGFLG
RADIANS OR DEGREES
BED6
F00A ~BEE2
BEQ
ATNOUT
RAD - FINI
BED8
A26B
LDX
#PIOV18i$FF
DEG - DIVIDE BY PI/1
BEDA
A0BE
LDY
*PIOV18/$100
BEDC
2098DD
JSR
FLD1R
BEDF
2028DB
JSR
FDIV
BEE 2
60
ATNOUT RTS
PI/4
SQR[X] — Square Root
BEE 3
38
BEE 4
60
BEE 5
A900
BEE 7
85F1
BEE9
A5D4
BEEB
30F6 "
BEED
C93F
BEEF
F017 *
BEF1
18
BEF2
6901
BEF4
85F1
BEF6
85E0
BEF8
A901
BEFA
85E1
BEFC
A204
BEFE
A900
BF00
95E2
BF02
CA
BF03
10FB "
BF05
2028DB
BF08
BF08
A906
BF0A
85EF
BF0C
A2E6
BF0E
A005
BF10
20A7DD
BF13
20B6DD
BF16
A293
BF18
A0BF
BF1A
2089DD
BF1D
2060DA
BF20
A2E6
BF22
A005
BF24
2098DD
BF27
20DBDA
BF2A
A2EC
BF2C
A005
BF2E
20A7DD
BF31
20B6DD
BF34
A2E6
BF36
A005
BF38
2089DD
SQRERR
SEC
;SET FAIL
RTS
SQR
LDA
#0
STA
XFMFLG
LDA
FR0
BMI
SQRERR
CMP
#$3F
BEQ
FSQR
; X IN RANGE OF APPROX
CLC
ADC
#1
STA
XFMFLG
,- NOT IN RANGE - TRANS
STA
FR1
; MANTISSA = 1
LDA
#1
STA
FR1 + 1
LDX
#FPREC-2
LDA
#0
SQR1
STA
FR1+2.X
DEX
BPL
SQR1
JSR
FDIV
; X/100**N
FSQR
;SQR[X], 0.1<=X<1.0
LDA
#6
STA
SQRCNT
LDX
#FSCRS.$FF
LDY
#FSCR/$100
JSR
FST0R
; STASH X IN FSCR
JSR
FMOVE
;X->FR1
LDX
#FTWOS,$FF
LDY
#FTWO/?100
JSR
FLD0R
,-2.0->FR0
JSR
FSUB
; 2 . 0-X
LDX
#FSCRi$FF
LDY
#FSCR/$100
JSR
FLD1R
;X->FR1
JSR
FMUL
;X*[2.0-X] :1ST APPROX
SQRLP
LDX
#FSCR16,$FF
LDY
#FSCR1/?100
JSR
FST0R
;Y->FSCR1
JSR
FMOVE
;Y->FR1
LDX
#FSCR6,$FF
LDY
#FSCR/$100
JSR
FLD0R
245
Source Code
BF3B
BF3E
BF40
BF42
BF45
BF48
BF4A
BF4C
BF4F
BF52
BF54
BF56
BF58
BF5A
BF5D
BF60
BF62
BF64
BF66
BF68
BF6B
BF6D
BF6F
BF70
BF72
BF73
BF73
BF74
BF75
BF77
BF79
BF7B
BF7D
BF7D
BF7E
BF80
BF82
BF84
BF86
BF88
BF8A
BF8C
BF8D
BF8F
BF92
BF93
2028DB
A2EC
A005
2098DD
2060DA
A26C
A0DF
2098DD
20DBDA
A5D4
F00E "BF64
A2EC
A005
2098DD
2066DA
C6EF
10C6 "BF2A
A2EC
A005
2089DD
A5F1
F023 "BF92
38
E940
18
+6A
18
6940
297F
85E0
A5F1
+6A
A901
9002
A910
85E1
A204
A900
95E2
CA
10FB
BF84
20DBDA
60
4002000000
00
JSR
LDX
LDY
JSR
JSR
LDX
LDY
JSR
JSR
LDA
BEQ
LDX
LDY
JSR
JSR
DEC
BPL
SQRDON LDX
LDY
JSR
; WAS
LDA
BEQ
SEC
SBC
CLC
RORA
ROR
CLC
ADC
AND
STA
LDA
RORA
ROR
LDA
BCC
LDA
SQR2 STA
LDX
LDA
SQR3 STA
DEX
BPL
JSR
FDIV
#FSCR1&?FF
#FSCR1/$100
FLD1R
FSUB
#FHALF&$FF
#FHALF/$100
FLD1R
FMUL
FR0
SQRDON
#FSCR1&$FF
#FSCR1/$100
FLD1R
FADD
SQRCNT
SQRLP
#FSCR1&$FF
#FSCR1/$100
FLD0R
ARG TRANSFORMED
XFMFLG
SQROUT
#$40
#?40
#$7F
FR1
XFMFLG
A
#1
SQR2
#$10
FR1 + 1
#FPREC-2
#0
FR1+2.X
SQR3
FMUL
;X/Y
;[X/Y]-Y
;0.5*[[X/Y]-Y]=DELTAY
; DELTA 0.0
;Y=Y+DELTA Y
; COUNT & LOOP
I DELTA = - GET Y BACK
YES - TRANSFORM RESULT
DIVIDE EXP BY 2
MANTISSA = 1
WAS EXP ODD OR EVEN
ODD - MANT =10
SQROUT
FTWO
RTS
.BYTE
$40,2,
; CLEAR REST OF MANTISSA
; SQR[X] = SQR[X/100**N]
* [10**N]
,0 ; 2.0
BF99
D800
Floating Point
ORG
LOCAL
ASCIN — Convert ASCII Input to Internal Form
INBUFF - POINTS TO BUFFER WITH ASCII
CIX - INDEX TO 1ST BYTE OF #
CC SET - CARRY SET IF NOT t
CARRY CLEAR OF t
D800
AFP
D800
CVAFP
D800
ASCIN
D800
20A1DB
JSR
SKPBLANK
D803
20BBDB
JSR
:TSTCHAR
D806
B039 "0841
BCS
:NONUM
SEE IF THIS COULD BE A NUMBER
BR IF NOT A NUMBER
246
Source Code
SET
INITI
D808
A2ED
LDX
#EEXP
D80A
A004
LDY
#4
D80C
2048DA
JSR
ZXLY
D80F
A2FF
LDX
#$FF
D811
86F1
STX
DIGRT
D813 2044DA
D816 F004 "D81C
ZERO 4 VALUES
X
X
SET TO SFF
CLEAR FR0
UNCONDITIONAL BR
D818
D818
A9FF
LDA
#$FF
D81A
85F0
STA
FCHRFLG
D81C
: IN2
D81C
2094DB
JSR
:GETCHAR
D81F
B021 "
D842
BCS
:NONl
IT'S A NUMBER
D821
48
PHA
D822
A6D5
LDX
FR0M
D824
D011 ~D837
BNE
:INCE
D826
20EBDB
JSR
NIBSH0
SET 1ST CHAR FLAG TO NON
ZERO
X
GET INPUT CHAR
BR IF CHAR NOT NUMBER
SAVE ON CPU STACK
GET 1ST BYTE
INCR EXPONENT
SHIFT FR0 ONE NIBBLE LEFT
D829 68
D82A 05D9
D82C 85D9
D82E A6F1
D830 30E6 *D818
D832 E8
D833 86F1
D835 D0E1 "D818
PLA
ORA FR0M+FMPREC-1
STA FR0M+FMPREC-1
GET DIGIT ON CPU STACK
OR INTO LAST BYTE
SAVE AS LAST BYTE
COUNT CHARACTERS AFTER DECIMAL POINT
LDX
BMI
I NX
STX
BNE
DIGRT
:IN1
DIGRT
:IN1
GET # OF DIGITS RIGHT
IF = $FF, NO DECIMAL POINT
ADD IN THIS CHAR
SAVE
GET NEXT CHAR
INCREMENT # OR DIGIT MORE THAN 9
D837
:INCE
D837
68
PLA
D838
A6F1
LDX
DIGRT
D83A
1002 "D83E
BPL
:INCE2
D83C
E6ED
INC
EEXP
D83E
:INCE2
D83E
4C18D8
JMP
: INI
D841
:NONUM
D841
60
RTS
CLEAR CPU STACK
HAVE DP?
IF YES, DON'T INCR E COUNT
INCR EXPONENT
GET NEXT CHAR
RETURN FAIL
NON-NUMERIC IN NUMBER BODY
D842
:NONl
D842
C92E
CMP
#' -'
D844
F014
"D85A
BEQ
:DP
D846
C945
CMP
#'E'
D848
F019
"D863
BEQ
:EXP
D84A
A6F0
LDX
FCHRFLG
D84C
D068
"D8B6
BNE
:EXIT
D84E
C92B
CMP
# '+'
IS IT DECIMAL POINT?
IF YES, PROCESS IT
IS IT E FOR EXPONENT?
IF YES, DO EXPONENT
IS THIS THE 1ST CHAR
IF NOT, END OF NUMERIC INPUT
IS IT PLUS?
247
Source Code
D850
F0C6
~D818
BEQ
:IN1
D852
C92D
CMP
#'-'
D854
F000
~D856
BEQ
: MINUS
D856
:MINUS
D856
85EE
STA
NSIGN
D858
F0BE
"D818
BEQ
: INI
D85A
:DP
D85A
A6F1
LDX
DIGRT
D85C
1058
"D8B6
BPL
:EXIT
D85E
E8
I NX
D85F
86F1
STX
DIGRT
D861
F0B5
~D818
BEQ
:IN1
D863
:EXP
D863
A5F2
LDA
CIX
D865
85EC
STA
FRX
D867
2094DB
JSR
:GETCHAR
D86A
B037
"D8A3
BCS
:N0N2
GO FOR NEXT CHAR
IS IT MINUS?
SAVE SIGN FOR LATER
UNCONDITIONAL BRANCH FOR
NEXT CHAR
IS DIGRT STILL = FF?
IF NOT, ALREADY HAVE DP
INCR TO ZERO
SAVE
UNCONDITIONAL BR FOR NEXT
CHAR
GET INDEX
SAVE
GET NEXT CHAR
BR IF NOT NUMBER
D86C
D86C
AA
D86D
A5ED
D86F
48
D870
86ED
D872
2094DB
D875
B017 *
D877
48
D878
A5ED
D87A
D87A
+0A
D87B
85ED
D87D
D87D
+0A
D87E
D87E
+0A
D87F
65ED
D881
85ED
D883
68
D884
18
D885
65ED
D887
85ED
D889
A4F2
D88B
209DDB
D88E
D88E
A5EF
D890
F009 "
D892
A5ED
D894
49FF
D896
18
D897
6901
D899
85ED
D89B
D89B
68
D89C
18
D89D
65ED
D89F
85ED
D8A1
D013 "
IT'S A NUMBER IN AN EXPONENT
EXP 2
TAX
LDA
PHA
STX
JSR
BCS
PHA
LDA
AS LA
ASL
STA
ASLA
ASL
ASLA
ASL
ADC
STA
PLA
CLC
ADC
STA
LDY
JSR
EEXP
:GETCHAR
A
EEXP
A
EEXP
EEXP
EEXP
EEXP
CIX
:GCHR1
3
LDA
ESIGN
BEQ
LDA
:EXP1
EEXP
EOR
CLC
#SFF
ADC
STA
1
#1
EEXP
PLA
CLC
ADC
EEXP
STA
EEXP
BNE
:EXIT
SAVE 1ST CHAR OF EXPONENT
GET # OF CHAR OVER 9
SAVE IT
SAVE 1ST CHAR OF EXPONENT
GET NEXT CHAR
IF NOT # NO SECOND DIGIT
SAVE SECOND DIGIT
GET 1ST DIGIT
GET DIGIT * 10
X
SAVE
GET SECOND DIGIT
GET EXPONENT INPUTTED
SAVE
INC TO NEXT CHAR
X
GET SIGN OF EXPONENT
IF NO SIGN, IT IS +
GET EXPONENT ENTERED
COMPLEMENT TO MAKE MINUS
X
X
SAVE
GET # DIGITS MORE THAN 9
CLEAR CARRY
ADD IN ENTERED EXPONENT
SAVE EXPONENT
UNCONDITIONAL BR
248
Source Code
NON-NUMERIC IN EXPONENT
D8A3
NON2
D8A3
C92B
CMP
D8A5
F006
"D8AD
BEQ
D8A7
C92D
CMP
D8A9
D007
"D8B2
BNE
D8AB
EMIN
D8AB
85EF
STA
D8AD
EPLUS
D8AD
2094DB
JSR
D8B0
90BA
"D86C
BCC
: EPLUS
:NOTE
:GETCHAR
:EXP2
IS IT PLUS?
IF YES BR
IS IT A MINUS?
IF NOT, BR
; SAVE EXPONENT SIGN
E NOT PART OF OUR #
D8B2
:NOTE
D8B2
A5EC
LDA
FRX
D8B4
85F2
STA
CIX
GET CHARACTER
IF A #, GO PROCESS EXPONENT
POINT TO 1 PAST E
RESTORE CIX
D8B6
D8B6 C6F2
FALL THRU TO EXIT
WHOLE # HAS BEEN INPUTTED
EXIT
BACK UP ONE CHAR
DEC CIX
; DECREMENT INDEX
D8B8
A5ED
LDA
EEXP
D8BA
A6F1
LDX
DIGRT
D8BC
3005
~D8C3
BMI
:EXIT1
D8BE
F003
"D8C3
BEQ
:EXITI
D8C0
38
SEC
D8C1
E5F1
SBC
DIGRT
D8C3
:EXIT1
D8C3
48
PHA
D8C4
ROLA
D8C4
+2A
ROL
A
D8C5
68
PLA
D8C6
RORA
D8C6
+6A
ROR
A
D8C7
85ED
STA
EEXP
D8C9
9003 "D8CE
BCC
:EVEN
D8CB
20EBDB
JSR
NIBSH0
D8CE
:EVEN
D8CE
A5ED
LDA
EEXP
D8D0
18
CLC
D8DI
6944
ADC
#$44
D8D3
85D4
STA
FR0
D8D5
2000DC
JSR
NORM
D8D8
B00B ~D8E5
BCS
: IND2
CALCULATE POWER OF 10 = EXP - DIGITS RIGHT
WHERE EXP = ENTERED EXPONENT [COMPLEMENT OF -]
+ # DIGITS MORE THAN 9
GET EXPONENT
GET # DIGITS RIGHT OF DECIMAL
NO DECIMAL POINT
# OF DIGITS AFTER D.P.=0
GET EXP - DIGITS RIGHT
X
SHIFT RIGHT ALGEBRAIC TO DIVIDE BY 2 = POWER OF 100
; SET CARRY WITH SIGN OF
EXPONENT
; GET EXPONENT AGAIN
; SHIFT RIGHT
; SAVE POWER OF 100
r IF NO CARRY # EVEN
; ELSE SHIFT 1 NIBBLE LEFT
; ADD 40 FOR EXCESS 64+4
FOR NORM
; X
,- X
; SAVE AS EXPONENT
; NORMALIZE NUMBER
; IF CARRY SET, IT'S AN ERROR
249
Source Code
SET MANTISSA SIGH
D8DA
A6EE
LDX
NSIGN
; IS SIGN OP # MINUS?
D8DC
F006
"D8E4
BEQ
: INDON
r IP NOT, BR
D8DE
A5D4
LDA
PR0
; GET EXPONENT
D8E0
0980
ORA
#?80
; TURN ON MINUS # BIT
D8E2
85D4
STA
FR0
; SET IN FR0 EXP
D8E4
:INDON
D8E4
18
CLC
; CLEAR CARRY
D8E5
:IND2
D8E5
60
RTS
FPASC — Convert Floating Point to ASCII
* ON ENTRY
FR0 - | TO CONVERT
*
*
*
ON
EXIT
D8E6
*
CVFASC
D8E6
FASC
D8E6
2051DA
JSR
INTLBF
D8E9
A930
LDA
t'0 1
D8EB
8D7F05
STA
LBUFF-1
INBUFF - POINTS TO START OF #
HIGH ORDER BIT OF LAST BYTE IS ON
;SET INBUFF TO PT TO LBUFF
GET ASCII ZERO
PUT IN FRONT OF LBUFF
TEST FOR E FORMAT REQUIRED
D8EE
A5D4
D8F0
F028
D8F2
297F
D8F4
C93F
D8F6
9028
D8F8
C945
D8FA
B024
D8FC
38
D8FD
E93F
D8FF 2070DC
D902
20A4DC
D905
0980
D907
9D8005
D90A
AD8005
D90D
C92E
D90F
F003 *D914
D911
4C88D9
D914
D914
20C1DC
D917
4C9CD9
LDA
PR0
BEQ
:EXP0
AND
#$7F
CMP
#$3F
BCC
:EFORM
CMP
#$45
BCS
:EFORM
PROCESS NOT E FORMAT
SEC
SBC
#$3F
JSR
:CVFR0
JSR
:FNZERO
ORA
#?80
STA
LBUFF, X
LDA
LBUFF
CMP
#' -'
BEQ
:FN6
JMP
:FN5
JSR
:DECINB
JMP
:FN4
GET EXPONENT
IF EXP = 0, # = 0, SO BR
AND OUT SIGN
IS IT LESS THAN 3F
IF YES, E FORMAT REQUIRED
IF IT IS > 44
IF YES, E FORMAT REQUIRED
SET CARRY
GET DECIMAL POSITION
CONVERT FR0 TO ASCII CHAR
FIND LAST NON-ZERO CHARACTER
TURN ON HIGH ORDER BIT
STORE IT BACK IN BUFFER
GET 1ST CHAR IN LBUFF
IS IT DECIMAL?
BR IF YES
ELSE JUMP
DECIMAL INBUFF
DO FINAL ADJUSTMENT
EXPONENT IS ZERO - # IS ZERO
D91A
D91A A9B0
D91C 8D8005
D91F 60
:EXP0
LDA
STA
RTS
#?80+$3£
LBUFF
GET ASCII WITH MSB
PUT IN BUFFER
PROCESS E FORMAT
:EFORM
A901
LDA
#1
2
2070DC
JSR
:CVFR0
GET DECIMAL POSITION
CONVERT FR0 TO ASCII
LBUFF
250
Source Code
D92 5
20A4DC
JSR
:FNZERO
D928
E8
I NX
D929
86P2
STX
CIX
ADJUST EXPO
D92B
A5D4
LDA
FR0
D92D
ASLA
D92D
+0A
ASL
A
D92E
38
SEC
D92F
E980
SBC
#S40*2
D931
AE8005
LDX
LBUFF
D934
E030
CPX
#'0'
D936
P017 ~D94F
BEQ
:EF1
PUT
DECIMAL
D938 AE8105
D93B AC8205
D93E 8E8205
D941 8C8105
GET RID OF TRAILING ZEROS
I NCR INDEX
SAVE INDEX TO LAST CHAR
GET EXPONENT
MULT BY 2 [GET RID OF
SIGN TOO]
SUB EXCESS 64
GET 1ST CHAR IN LBUFF
IS IT ASCII 0?
PUT DECIMAL AFTER 1ST CHAR [IT'S AFTER 2ND NOW]
LDX LBUFF+1
LDY LBUFF+2
STX LBUFF+2
STY LBUFF+1
SWITCH D.P. + 2ND DIGIT
X
X
X
D944 A6F2
D946 E002
D948 D002 "D94C
D94A E6F2
D94C
D94C
18
D94D
6901
D94F
D94F
85ED
D951
A945
D953
A4F2
D955
209FDC
D958
84F2
LDX
CIX
CPX
#2
BNE
: NOINC
INC
CIX
NOINC
CLC
ADC
#1
CONVERT EXP TO ASCII
STA EEXP
LDA # ' E '
LDY CIX
JSR rSTCHAR
STY CIX
IF CIX POINTS TO D.P.
THEN INC
X
X
X
X
SAVE EXPONENT
GET ASCII E
GET POINTER
STORE CHARACTER
SAVE INDEX
D95A A5ED
D95C 100B "D969
D95E A900
LDA
BPL
EEXP
:EPL
; GET EXPONENT
; BR IF PLUS
D960
38
D961
E5ED
D963
85ED
D965
A92D
D967
D002 "D96B
D969
D969
A92B
D96B
D96B
209FDC
D96E
A200
D970
A5ED
D972
D972
38
D973
E90A
EXPONENT IS MINUS - COMPLEMENT IT
SEC
SBC
STA
LDA
BNE
:EF2
LDX
LDA
SEC
SBC
#0
EEXP
EEXP
:EF2
:STCHAR
#0
EEXP
#10
; SUBTRACT FROM TO
COMPLEMENT
; X
; X
GET A MINUS
GET A PLUS
STORE A CHARACTER
SET COUNTER FOR # OF TENS
GET EXPONENT
; SUBTRACT 10
251
Source Code
D975
9003 *
D97A
BCC
:EF4
D977
E8
I NX
D978
D0F8 *
D972
BNB
:EF3
D97A
:EF4
D97A
18
CLC
D97B
690A
ADC
#10
D97D
48
PHA
D97E
8A
TXA
D97F
209DDC
JSR
:STNUM
D982
68
PLA
D983
0980
ORA
#$80
D985
209DDC
JSR
:STNUM
IF < 0, BRANCH
INCR # OF 10' S
BR UNCONDITIONAL
ADD BACK IN 10
X
SAVE
GET # OF 10' S
PUT 10 'S IN EXP IN BUFFER
GET REMAINDER
TURN ON HIGH ORDER BIT
PUT IN BUFFER
FINAL ADJUSTMENT
D988
D988
AD8005
D98B
C930
D98D
D00D "D99C
D98F
18
D990
A5F3
D992
6901
D994
85F3
D996
A5F4
D998
6900
D99A
85F4
D99C
D99C
A5D4
D99E
1009 "D9A9
D9A0
20C1DC
D9A3
A000
D9A5
A92D
D9A7
91F3
D9A9
D9A9
60
LDA
LBUFF
CMP
#'0'
BNE
:FN4
INCREMENT INBU
CLC
LDA
INBUFF
ADC
#1
STA
INBUFF
LDA
INBUFF+1
ADC
#0
STA
INBUFF+1
:FN4
LDA
FR0
BPL
: FADONE
JSR
rDECINB
LDY
#0
LDA
#'-'
STA
[INBUFF], Y
: FADONE
RTS
GET 1ST BYTE IN LBUFF
[OUTPUT]
IS IT ASCII 0?
IF NOT BR
ADD 1 TO INBUFF
X
X
X
X
X
X
GET EXPONENT OF #
IF SIGN +, WE ARE DONE
DECR INBUFF
GET INDEX
GET ASCII -
SAVE - IN BUFFER
IFP — Convert Integer to Floating Point
ON ENTRY
ON EXIT
FR0 - CONTAINS INTEGER
FR0 - CONTAINS FLOATING POINT #
D9AA
D9AA
D9AA
A5D4
D9AC
85F8
D9AE
A5D5
D9B0
85F7
D9B2
2044DA
D9B5
F8
D9B6
A010
D9B8
D9B8
06F8
D9BA
26F7
CVIFP
IFP
MOVE INTEGER AND REVERSE BYTES
LDA
STA
LDA
STA
JSR
SED
FR0
ZTEMP4+1
FR0+1
ZTEMP4
ZFR0
DO THE CONVERT
LDY
:IFP1
ASL
ROL
116
ZTEMP4+1
ZTEMP4
GET INTEGER LOW
SAVE AS INTEGER HIGH
GET INTEGER HIGH
SAVE AS INTEGER LOW
CLEAR FR0
SET DECIMAL MODE
; GET # BITS IN INTEGER
SHIFT LEFT INTEGER LOW
SHIFT LEFT INTEGER HIGH
252
Source Code
D9BC A203
D9BE
D9BE B5D4
D9C0 75D4
D9C2 95D4
D9C4 CA
D9C5 D0F7 "D9BE
D9C7 88
D9C8 D0EE "D9B8
D9CA D8
D9CB A942
D9CD 85D4
D9CF 4C00DC
LDX
:IFP2
CARRY NOW SET IF THERE WAS A
BIT
BIGGEST INTEGER IS 3 BYTES
DOUBLE # AND ADD IN 1 IF CARRY SET
LDA
FR0, X
ADC
FR0.X
STA
FR0,X
DEX
BNE
:IFP2
DEY
BNE
:IFP1
CLD
j SET
EXPONENT
LDA
#$42
STA
FR0
JMP
NORM
GET BYTE
DOUBLE [ADDING IN CARRY
FROM SHIFT
SAVE
DECREMENT COUNT OF FR0 BYTES
IF MORE TO DO, DO IT
DECR COUNT OF INTEGER DIGITS
IF MORE TO DO, DO IT
CLEAR DECIMAL MODE
INDICATE DECIMAL AFTER LAST
DIGIT
STORE EXPONENT
I NORMALIZE
FPI — Convert Floating Point to Integer
* ON ENTRY FR0
ON EXIT
FLOATING POINT NUMBER
FR0 - INTEGER
CC SET CARRY CLEAR - NO ERROR
CARRY SET - ERROR
CLEAR INTEGER
D9D2
A900
LDA
#0
D9D4
85F7
STA
ZTEMP4
D9D6
85F8
STA
ZTEMP4+1
CHECK EXPONE
D9D8
A5D4
LDA
FR0
D9DA
3066
"DA42
BMI
: ERVAL
D9DC
C943
CMP
#$43
D9DE
B062
~DA42
BCS
: ERVAL
D9E0
38
SEC
D9E1
E940
SBC
#$40
D9E3
903F
"DA24
BCC
: ROUND
D9E5 6900
D9E7
D9E7 +0A
D9E8 85F5
,- CLEAR INTEGER RESULT
GET EXPONENT
IF SIGN OF FP# IS -, THEN
ERROR
IS FP# TOO BIG TO BE INTEGER
IF YES, THEN ERROR
SET CARRY
IS FP# LESS THAN 1?
IF YES, THEN GO TEST FOR
ROUND
GET # OF DIGITS TO CONVERT
[A CONTAINS EXPONENT -40]
[CARRY SET]
[EXPONENT -40+1 ]*2
ADC
#0
ASLA
ASL
A
STA
ZTEMP1
DO
CONVERT
; ADD IN CARRY
; MULT BY 2
SAVE AS COUNTER
253
Source Code
MULT INTEGER RESULT BY 10
D9EA 205ADA
D9ED B053 "DA42
D9EF
A5F7
D9F1
85F9
D9F3
A5F8
D9F5
85FA
D9F7
205ADA
D9FA
B046
~DA42
D9FC
205ADA
D9FF
B041
"DA42
DA01
18
DA02
A5F8
DA04
65FA
DA06
85F8
DA08
A5F7
DA0A
65F9
DA0C
85F7
DA0E
B032
"DA42
JSR
ILSHFT ;
BCS
ERVAL ;
LDA ZTEMP4 ;
STA ZTEMP3 ;
LDA ZTEMP4+1 ;
STA ZTEMP3+1 ;
JSR
ILSHFT i
BCS
ERVAL j
JSR
ILSHFT ;
BCS
ERVAL
CLC
LDA ZTEMP4+1 ;
ADC ZTEMP3+1 ;
STA ZTEMP4+1 ;
LDA ZTEMP4 ;
ADC ZTEMP3 ;
STA ZTEMP4 ;
BCS
ERVAL ;
GO SHIFT ONCE LEFT
IF CARRY SET THEN # TOO BIG
SAVE INTEGER *2
X
X
X
MULT BY *2
# TOO BIG
MULT BY *2 [NOW
BR IF # TOO BIG
8 IN ZTEMP4]
ADD IN * 2 TO = *1B
X
X
X
X
X
X
IF CARRY SET ERROR
ADD IN NEXT DIGIT
DA10
20B9DC
JSR
:GETDIG
DAI 3
18
CLC
DA14
65F8
ADC
ZTEMP4+1
DA16
85F8
STA
ZTEMP4+I
DA18
A5F7
LDA
ZTEMP4
DAI A
6900
ADC
#0
DA1C
B024
"DA42
BCS
: ERVAL
DA1E
85F7
STA
ZTEMP4
DA20
C6F5
"
DEC
ZTEMP1
DA22
D0C6
"D9EA
BNE
:FPI1
ROUND IF NEEDED
DA24
: ROUND
DA24
20B9DC
JSR
:GETDIG
DA27
C905
CMP
#5
DA29
900D "DA38
BCC
:NR
DA2B
18
CLC
DA2C
A5F8
LDA
ZTEMP4+1
DA2E
6901
ADC
#1
DA30
85F8
STA
ZTEMP4+1
DA32
A5F7
LDA
ZTEMP4
DA34
6900
ADC
#0
DA36
85F7
STA
ZTEMP4
GET DIGIT IN A
ADD IN DIGIT
X
X
X
BR IF OVERFLOW
DEC COUNTER OF DIGITS TO DO
IF MORE TO DO, DO IT
GET NEXT DIGIT IN A
IS DIGIT <5?
IF YES, DON'T ROUND
ADD IN 1 TO ROUND
X
X
X
X
X
X
MOVE INTEGER TO FR0
DA38
DA38
A5F8
DA3A
85D4
DA3C
A5F7
DA3E
85D5
DA40
18
DA41
60
DA42
DA42
38
DA43
60
LDA
STA
LDA
STA
CLC
RTS
ERVAL
SEC
RTS
ZTEMP4+1
FR0
ZTEMP4
FR0+1
GET INTEGER LOW
SAVE
GET INTEGER HIGH
SAVE
CLEAR CC FOR GOOD RETURN
SET CARRY FOR ERROR RETURN
ZFR0 - ZERO FR0
ZF1 - ZERO 6 BYTES AT LOC X
254
Source Code
ZXLY - ZERO PAGE ZERO LOC X FOR LENGTH Y
DA44
DA44
A2D4
DA46
DA46
A006
DA48
DA48
A900
DA4A
DA4A
9500
DA4C
E8
DA4D
88
DA4E
D0FA
DA50
60
LDY
#6
LDA
#0
STA
0.
INX
DEY
BNE
:Z
RTS
GET POINTER TO FR1
GET # OF BYTES TO CLEAR
CLEAR A
CLEAR A BYTE
POINT TO NEXT BYTE
DEC COUNTER
LOOP
INTLBF - INIT LBUFF INTO INBUFF
DA51
DA51
A905
DA53
85F4
DA55
A980
DA57
85F3
DA59
60
DA5A
DA 5 A
DA 5 A
18
DA5B
26F8
DA5D
26F7
DA5F
60
INTLBF
LDA
#LBUFF/256
STA
INBUFF+1
LDA
#LBUFF&255
STA
INBUFF
RTS
*
*
: ILSHFT - SHIF
ILSHFT
:ILSHFT
CLC
ROL
ZTEMP4+1
ROL
ZTEMP4
RTS
SHIFT INTEGER IN ZTEMP4 LEFT ONCE
CLEAR CARRY
SHIFT LOW
SHIFT HIGH
Floating Point Routines
FADD — Floating Point Add Routine
ADDS VALUES IN FR0 AND FR1
*
* ON ENTRY FR0 6> FR1 - CONTAIN # TO ADD
*
* ON EXIT FR0 - RESULT
FSUB — Floating Point Subtract Routine
* SUBTRACTS FR1 FROM FR0
*
* ON ENTRY FR0 S, FR1 - CONTAIN # TO SUBTRACT
*
* ON EXIT FR0 - RESULT
*
* BOTH RETURN WITH CC SET:
* CARRY SET IF ERROR
* CARRY CLEAR IF NO ERROR
DA60
DA60 A5E0
DA62 4980
DA64 85E0
LDA
EOR
STA
FRI
#$80
FRI
GET EXPONENT OF FRI
CHANGE SIGN OF MANTISSA
SAVE EXPONENT
DA66
DA66
FADD
:FRADD
255
Source Code
DA66
A5E0
DA68
297P
DA6A
85F7
DA6C
A5D4
DA6E
297F
DA70
38
DA71
E5P7
DA73
1010 "DA85
LDA
AND
STA
LDA
AND
SEC
SBC
BPL
FR1
#$7F
ZTEMP4
FR0
#$7F
ZTEMP4
:NSWAP
DA75 A205
SWAP FR0 AND FR1
LDX KFMPREC
GET EXPONENT FR1
TURN OFF MANTISSA SIGN BIT
SAVE TEMPORARILY
GET EXPONENT FR0
TURN OFF MANTISSA SIGN BIT
CLEAR CARRY
SUB EXPONENTS
IF EXP[FR0]>= EXP[FR1],
NO SWAP
GET INDEX
DA77
:SWAP
DA77
B5D4
LDA
DA79
B4E0
LDY
DA7B
95E0
STA
DA7D
98
TYA
DA7E
95D4
STA
DA80
CA
DEX
DA81
10F4
"DA77
BPL
DA83
30E1
~DA66
BMI
DA85
:NSWAP
DA85
F007
"DA8E
BEQ
DA87
C905
CMP
DA89
B019
"DAA4
BCS
DA8B
203EDC
JSR
FR0,X
FR1,X
FR1.X
FR0,X
:SWAP
:FRADD
»FMPREC
: ADDEND
GET BYTE FROM FR0
GET BYTE FROM FR1
PUT FR0 BYTE IN FR1
GET FR1 BYTE
PUT FR1 BYTE IN FR0
DEC INDEX
IF MORE TO DO, GO SWAP
UNCONDITIONAL
IF DIFFERENCE = 0, ALREADY
ALIGNED
IS DIFFERENCE < I OF BYTES
IF NOT, HAVE RESULT IN FR0
RSHFT1 ;
TEST FOR LIKE SIGN OF
DA8E
:NALIGN
DA8E
F8
SED
DA8F
A5D4
LDA
FR0
DA91
45E0
EOR
FR1 ;
DA93
30 IE "DAB 3
BMI
:SUB ;
; ADD
FR0 & FR1
DA95
A204
LDX
#FMPREC-1 ;
DA97
18
CLC
DA98
:ADD1
DA98
B5D5
LDA
FR0M.X ;
DA9A
75E1
ADC
FR1M,X ;
DA9C
95D5
STA
FR0M,X ;
DA9E
CA
DEX
DA9F
10F7 "DA98
BPL
:ADD1 !
DAA1
D8
CLD
DAA2
B003 ~DAA7
BCS
:ADD2 ;
DAA4
: ADDEND
DAA4
4C00DC
JMP
NORM ;
; ADD
IN FIND CARRY
DAA7
:ADD2
DAA7
A901
LDA
#i ;
DAA9
203ADC
JSR
RSHFT0 ;
DAAC
A901
LDA
#01 ;
DAAE
85D5
STA
FR0M ;
DAB0
4C00DC
JMP
NORM
SHIFT TO ALIGN
MANTISSA
SET DECIMAL MODE
GET FR0 EXPONENT
EOR WITH FR1 EXPONENT
IF SIGNS DIFFERENT - SUBTRACT
ELSE ADD
GET POINTER FOR LAST BYTE
CLEAR CARRY
GET BYTE OF FR0
ADD IN BYTE OF FR1
STORE
DEC POINTER
ADD NEXT BYTE
CLEAR DECIMAL MODE
IF THERE IS A CARRY, DO IT
GO NORMALIZE
GET 1 TIMES TO SHIFT
GO SHIFT
GET CARRY
ADD IN CARRY
DAB 3
DAB3 A204
DAB 5 38
SUBTRACT FR1 FROM FR0
LDX
SEC
#FMPREC-1
GET POINTER TO LAST BYTE
SET CARRY
256
Source Code
DAB 6
:SUB1
DAB 6
B5D5
LDA
FR0M.X
DAB 8
F5E1
SBC
FR1M,X
DABA
95D5
STA
FR0M.X
DABC
CA
DEX
DABD
10F7
"DAB 6
BPL
:SUB1
DABF
9004
"DAC5
BCC
:SUB2
DAC1
D8
CLD
DAC2
4C00DC
JMP
NORM
DAC5
DAC5 A5D4
DAC7 4980
DAC9 85D4
SUB2
LDA
EOR
STA
TAKE COMPLEMENT SIGN
FR0
#$80
FR0
COMPLEMENT MANTISSA
GET FR0 BYTE
SUB FR1 BYTE
STORE
DEC POINTER
SUB NEXT BYTE
IF THERE IS A BORROW DO IT
CLEAR DECIMAL MODE
GET EXPONENT
CHANGE SIGN OF MANTISSA
PUT IT BACK
DACB
38
DACC
A204
DACE
DACE
A900
DAD0
F5D5
DAD2
95D5
DAD4
CA
DAD5
10F7 *
DAD7
D8
DAD8
4C00DC
SEC
LDX
:SUB3
LDA
SBC
STA
DEX
BPL
CLD
JMP
#FMPREC-1
#0
FR0M,X
FR0M.X
:SUB3
SET CARRY
GET INDEX COUNTER
GET ZERO
COMPLEMENT BYTE
STORE
MORE TO DO
BR IF YES
; CLEAR DECIMAL MODE
I GO NORMALIZE
FMUL — Multiply FRO by FR1
ON ENTRY # ARE IN FR0 AND FR1
ON EXIT FR0 - CONTAINS PRODUCT
RETURN WITH CC SET
CARRY SET IF ERROR
CARRY CLEAR IF NO ERROR
SET UP EXPONENT
DADB
A5D4
LDA
DADD
F045 "DB24
BEQ
DADF
A5E0
LDA
DAE1
F03E "DB21
BEQ
DAE 3
20CFDC
JSR
DAE 6
38
SEC
DAE 7
E940
SBC
DAE 9
38
SEC
DAEA
65E0
ADC
DAEC
3038 "DB26
BMI
FR0
MEND3
FR1
MEND2
MDESUP
#540
FR1
:EROV
GET EXP FR0
IF = 0, DONE
GET FR1 EXP
IF =0, ANSWER =0
DO COMMON SET FOR EXPONENT
SET CARRY
SUB EXCESS 64
SET CARRY TO ADD 1
ADD 1 + FR1 EXP TO FR0 EXP
IF - THEN OVERFLOW
FINISH MULTIPLY SET UP
DAEE 20E0DC
DO SET UP COMMON TO DIVIDE
DO THE MULTIPLY
GET * OF TIMES TO ADD IN MULTIPLICAND
257
Source Code
DAFl
A5DF
LDA
FRE+FMPREC
DAF3
290F
AND
#$0F
DAF5
85F6
STA
ZTEMP1+1
ADD
IN FR1
DAF7
FRM1
DAF7
C6F6
DEC
ZTEMP1+1
DAF9
3006 ~DB01
BMI
:FRM2
DAFB
2001DD
JSR
FRA10
DAFE
4CF7DA
JMP
:FRM1
GET LAST BYTE OF FRE
AND OUT HIGH ORDER NIBBLE
SET COUNTER FOR LOOP CONTROL
DEC MULT COUNTER
IF - THIS LOOP DONE
ADD FR1 TO FR0 [6 BYTES]
REPEAT
DB01
FRM2
DB01
A5DF
LDA
FRE+FMPREC
DB03
LSRA
DB03
DB04
+4A
LSR
LSRA
A
DB04
+4A
LSR
A
DB05
LSRA
DB05
+4A
LSR
A
DB06
LSRA
DB06
+4A
LSR
A
DB07
85F6
STA
ZTEMP1+1
ADD
IN FR2
DB09
FRM3
DB09
C6F6
DEC
ZTEMP1+1
DB0B
3006 "DB13
BMI
:NXTB
DB0D
2005DD
JSR
FRA20
DB10
4C09DB
JMP
:FRM3
GET # OF TIMES TO ADD IN MULTIPLICAND * 10
; GET LAST BYTE OF FRE
; SHIFT OUT LOW ORDER NIBBLE
; X
; x
; x
; SAVE AS COUNTER
DECREMENT COUNTER
IF -, DO NEXT BYTE
ADD FR2 TO FR0 [6 BYTES]
REPEAT
DB13 2062DC
DB16 C6F5
DB18 D0D7 "DAFl
SET UP FOR NEXT SET OF ADDS
TB
SHIFT FR0/FRE RIGHT ONE BYTE
[THEY ARE CONTIGUOUS]
JSR RSHF0E ; SHIFT FR0/FRE RIGHT
TEST FOR # OF BYTES SHIFTED
DEC
BNE
ZTEMP1
:FRM
DECREMENT LOOP CONTROL
IF MORE ADDS TO DO, DO IT
SET EXPONENT
DB1A
MDEND
DB1A
A5ED
LDA
EEXP
DB1C
85D4
STA
FR0
DB1E
MEND1
DB1E
4C04DC
JMP
NORM
DB21
MEND2
DB21
2044DA
JSR
ZFR0
DB24
MEND3
DB24
18
CLC
DB25
60
RTS
GET EXPONENT
STORE AS FR0 EXP
; NORMALIZE
CLEAR FR0
CLEAR CARRY FOR GOOD RTN
DB26
DB26 38
D327 60
:EROV
SEC
RTS
SET CARRY FOR ERROR ROUTINE
RETURN
258
Source Code
FDIV — Floating Point Divide
ON ENTRY
FR0 -
FR1 ■
- DIVIDEND
- DIVISOR
ON EXIT
FR0
- QUOTIENT
RETURNS WITH CC SET:
CARRY CLEAR - ERROR
CARRY SET - NO ERROR
DO
DIVIDE SET UP
DB28
A5E0
LDA
FR1
DB2A
F0FA ~DB26
BEQ
:EROV
DB2C
A5D4
LDA
FR0
DB2E
F0F4 ~DB24
BEQ
MEND3
DB30
20CFDC
JSR
MDESUP
DB33
38
SEC
DB34
E5E0
SBC
FR1
DB36
18
CLC
DB37
6940
ADC
#540
DB39
30EB *DB26
BMI
:EROV
DB3B
20E0DC
JSR
MDSUP
DB3E
E6F5
INC
ZTEMP1
DB40
4C4EDB
JMP
:FRD1
= 00D9
QTEMP
EQU
FR0+FMPREC
DB43
:NXTQ
GET FR1 EXP
IF =0, THEN OVERFLOW
GET EXPONENT FR0
IF = 0, THEN DONE
DO COMMOM PART OF EXP SET UP
; SUB FR1 EXP FROM FR0 EX
; ADD IN EXCESS 64
; IF MINUS THEN OVERFLOW
; DO SETUP COMMON FOR MULT
;LOOP 1 MORE TIME FOR DIVIDE
; SKIP SHIFT 1ST TIME THROUGH
SHIFT FR0/FRE LEFT ONE BYTE
[THEY ARE CONTIGUOUS]
DB43
A200
LDX
#0
DB45
:NXTQ1
DB45
B5D5
LDA
FR0+1,X
DB47
95D4
STA
FR0,X
DB49
E8
INX
DB4A
E00C
CPX
#FMPREC*2+2
DB4C
D0F7
"DB45
BNE
:NXTQ1
*
DO
DIVIDE
GET POINTER TO BYTE TO MOVE
GET BYTE
MOVE IT LEFT ONE BYTE
POINT TO NEXT BYTE
HAVE WE DONE THEM ALL?
IF NOT, BRANCH
DB4E
A005
LDY
#FMPREC
DB50
38
SEC
DB51
F8
SED
DB52
:FRS2
DB52
B9DA00
LDA
FRE, Y
DB55
F9E600
SBC
FR2, Y
DB58
99DA00
STA
FRE, Y
DB5B
88
DEY
DB5C
10F4 "DB52
BPL
:FRS2
DB5E
D8
CLD
DB5F
9004 "DB65
BCC
:FAIL
DB61
E6D9
INC
QTEMP
SUBTRACT FR2 [DIVISOR * 2] FROM FRE [DIVIDEND]
SET LOOP CONTROL
SET CARRY
SET DECIMAL MODE
; GET A BYTE FROM FRE
; SUB FR2
; STORE RESULT
; DEC COUNTER
; BR IF MORE TO DO
; CLEAR DECIMAL MODE
■ IF RESULT <0 [FRE < FR2 ] BR
; INCR # TIMES SUB [QUOTIENT]
259
Source Code
DB63 D0E9 ~DB4E
DB65
FAIL
DB65
200FDD
JSR
FRA2E
SHIFT LAS
DB68
06D9
ASL
QTEMP
DB6A
06D9
ASL
QTEMP
DB6C
06D9
ASL
QTEMP
DB6E
06D9
ASL
QTEMP
DB70
FRD2
BNE :FRD1 ; SUB AGAIN
SUBTRACT OF FR2 DIDN'T GO
I ADD FR2 BACK TO FR0
SHIFT LAST BYTE OF QUOTIENT ONE NIBBLE LEFT
SHIFT 4 BITS LEFT
X
X
X
SUBTRACT FR1 [DIVISOR] FROM FRE [DIVIDEND]
DB70
A005
LDY
#FMPREC
DB72
38
SEC
DB73
F8
SED
DB74
:FRS1
DB74
B9DA00
LDA
FRE, Y
DB77
F9E000
SBC
FR1,Y
DB7A
99DA00
STA
FRE, Y
DB7D
88
DEY
DB7E
10F4 *
DB74
BPL
:FRS1
DB80
D8
CLD
DB81
9004 *
DB87
BCC
:FAIL2
DB83
E6D9
INC
QTEMP
DB85
D0E9 *
DB70
BNE
:FRD2
SET LOOP CONTROL
SET CARRY
SET DECIMAL MODE
GET A BYTE FROM FRE
SUB FR1
STORE RESULT
BR IF MORE TO DO
CLEAR DECIMAL MODE
IF RESULT < [FRE < FR1] BR
INCR # TIMES SUB [QUOTIENT]
SUB AGAIN
SUBTRACT OF FR1 DIDN'T GO
DB87
:FAIL2
DB87
2009DD
JSR
FRA1E
DB8A
C6F5
DEC
ZTEMP1
DB8C
D0B5 "DB43
BNE
:NXTQ
DB8E
2062DC
JSR
RSHF0E
DB91
4C1ADB
JMP
MDEND
:GETCHAR — Testlni
mt Character
ON ENTRY
| ADD FR1 BACK TO FR0
I DEC LOOP CONTROL
; GET NEXT QUIOTIENT BYTE
; SHIFT RIGHT FR0/FRE TO CLEAR
EXP
j JOIN MULT END UP CODE
INBUFF - POINTS TO BUFFER WITH INPUT
CIX - POINTS TO CHAR IN BUFFER
CIX - POINTS TO NEXT CHAR
CC - CARRY CLEAR IF CHAR IS NUMBER
CARRY SET IF CHAR NOT NUMBER
DB94
:GETCHAR
DB94
20AFDB
JSR
TSTNUM
DB97
A4F2
LDY
CIX
DB99
9002 "DB9D
BCC
:GCHR1
DB9B
B1F3
LDA
[INBUFF], Y
DB9D
:GCHR1
DB9D
C8
I NY
DB9E
84F2
STY
CIX
DBA0
60
RTS
GO TEST FOR NUMBER
GET CHARACTER INDEX
IF CHAR = NUM, SKIP
GET CHARACTER
POINT TO NEXT CHAR
SAVE INDEX
;SKPBLANK-SKIP BLANKS
STARTS AT CIX AND SCANS FOR NON BLANKS
260
Source Code
DBAl
SKBLANK
DBAl
SKPBLANK
DBAl
A4F2
LDY
CIX
;GET CIX
DBA 3
A920
LDA
#520
;GET A BLANK
DBA 5
D1F3
tSBl
CMP
[INBUFF],
Y ;IS CHAR A
BLANK
DBA7
D003
"DBAC
BNE
:SBRTS
BR IF NOT
DBA9
C8
I NY
INC TO NEXT
DBAA
D0F9
"DBA5
BNE
:SB1
GO TEST
DBAC
84F2
:SBRTS
STY
CIX
;SET NON BLANK
INDEX
DBAE
60
RTS
; RETURN
; TSTNUM
-TEST CHAR AT CIX FOR NUM
- RTNS CARRY
SET
IF NUM
DBAF
TSTNUM
DBAF
A4F2
LDY
CIX
;GET INDEX
DBB1
B1F3
LDA
[INBUFF],
Y
;AND GET CHAR
DBB3
38
SEC
DBB4
E930
SBC
#?30
SUBTRACT ASCLT ZERO
DBB6
9018
"DBD0
BCC
:TSNFAIL
BR CHAR<ASCLT
ZERO
DBB8
C90A
CMP
#$0A
TEST GT ASCLT
9
DBBA
60
RTS
DONE
:TSTCHAR — Test to See if This Can Be a Number
* ON
*
EXIT C
DBBB
*
tTSTCHAR
DBBB
A5F2
LDA
CIX
DBBD
48
PHA
DBBE
2094DB
JSR
:GETCHAR
DBC1
901F
"DBE2
BCC
:RTPASS
DBC3
C92E
CMP
#' . '
DBC5
F014
"DBDB
BEQ
:TSTN
DBC7
C92B
CMP
#'+'
DBC9
F007
"DBD2
BEQ
:TSTN1
DBCB
C92D
CMP
#'-'
DBCD
F003
"DBD2
BEQ
:TSTN1
DBCF
:RTFAIL
DBCF
RTFAIL
DBCF
68
PLA
DBD0
38
TSNFAIL
SEC
DBD1
60
RTS
DBD2
TSTN1
DBD2
2094DB
JSR
:GETCHAR
DBD5
900B
"DBE2
BCC
: RTPASS
DBD7
C92E
CMP
#'.'
DBD9
D0F4
"DBCF
BNE
: RTFAIL
DBDB
TSTN
DBDB
2094DB
JSR
:GETCHAR
DBDE
9002
"DBE2
BCC
: RTPASS
DBE0
B0ED
"DBCF
BCS
: RTFAIL
DBE2
RTPASS
DBE2
68
PLA
DBE3
85F2
STA
CIX
DBE5
18
CLC
DBE6
60
RTS
CC - CARRY SET IF NOT A #
CARRY CLEAR IF A #
GET INDEX
SAVE IT
GET CHAR
IF = #8 RETURN PASS
IF = D.P. , OK SO FAR
IF = +8 OK SO FAR
IF = -8 OK SO FAR
; CLEAR STACK
;SET FAIL
GET CHAR
IF #, RETURN PASS
IS IT D.P.
IF NOT, RETURN FAIL
ELSE GET NEXT CHAR
IF #, RETURN PASS
ELSE, RETURN FAIL
RESTORE CIX
X
CLEAR CARRY
RETURN PASS
NIBSHO — Shift FRO One Nibble Left
* NIBSH2 - SHIFT FR2 ONE NIBBLE LEFT
DBE7
DBE7 A2E7
NIBSH2
LDX
#FR2+1
POINT TO 1ST MANTISSA BYTE
261
Source Code
DBE9 D002 "DBED
DBEB
DBEB
A2D5
DBED
DBED
A004
DBEF
DBEF
18
DBF0
3604
DBF2
3603
DBF4
3602
DBF6
3601
DBF8
3600
DBFA
26EC
DBFC
88
DBFD
D0F0
DBFF
60
NORM — N
DC00
DC00
A200
DC02
86DA
DC04
DC04
A204
DC06
A5D4
DC08
F02E
DC0A
DC0A
A5D5
DC0C
D01A
LDX
#FR0M
:NIB1
LDY
#4
:NIBS
CLC
ROL
4,X
ROL
3,X
ROL
2,X
ROL
l.X
ROL
0,X
ROL
FRX
DEY
BNE
:NIBS
RTS
"DC38
DC0E
A000
DC10
DC10
B9D600
DC13
99D500
DC16
C8
DC17
C005
DC19 90F5 ~DC10
DC1B C6D4
NORM
LDX
#0
STX
FR0+FPREC
NORM1
LDX
#FMPREC-1
LDA
FR0
BEQ
:NDONE
:NORM
LDA
FR0M
BNE
:TSTBIG
SHIFT 1 BYTE
LDY
#0
:NSH
LDA
FR0M+1, Y
STA
FR0M, Y
INY
CPY
#FMPREC
BCC
:NSH
POINT TO MANTISSA OF FR0
GET # OF BITS TO SHIFT
CLEAR CARRY
ROLL
X
X
X
X
SAVE SHIFTED NIBBLE
DEC COUNT
IF NOT = 0, REPEAT
GET ZERO
FOR ADD NORM SHIFT IN A ZERO
GET MAX # OF BYTES TO SHIFT
GET EXPONENT
IF EXP=0, # =0
GET 1ST BYTE OF MANTISSA
IF NOT = THEN NO SHIFT
GET INDEX FOR 1ST MOVE BYTE
DECREMENT EXPONENT
DEC FR0
GET MOVE BYTE
STORE IT
ARE WE DONE
IF NOT SHIFT AGAIN
DECREMENT EXPONENT
DC1D
CA
DEX
DC1E
D0EA
"DC0A
BNE
:NORM
DC20
A5D5
LDA
FR0M
DC22
D004
"DC28
BNE
:TSTBIG
DC24
85D4
STA
FR0
DC26
18
CLC
DC27
60
RTS
DC28
:TSTBIG
DC28
A5D4
LDA
FR0
DC 2 A
297F
AND
#$7F
DC2C
C971
CMP
#49+64
DC2E
9001
"DC31
BCC
:TSTUND
DC30
60
RTS
DC31
:TSTUND
DC31
C90F
CMP
#-49+64
DC33
B003
"DC38
BCS
:NDONE
DC35
2044DA
JSR
ZFR0
DC38
:NDONE
DC38
18
CLC
DC39
60
RTS
DEC COUNTER
DO AGAIN IF NEEDED
IS MANTISSA STILL
IF NOT, SEE IF TOO BIG
ELSE ZERO EXP
GET EXPONENT
AND OUT SIGN BIT
IS IT < 49+64?
IF YES, TEST UNDERFLOW
SO RETURN
IS IT >=-49+64?
IF YES, WE ARE DONE
ELSE # IS ZERO
CLEAR CARRY FOR GOOD RETURN
262
Source Code
RSHFTO — Shift FRO Right/Increment Exponent
RSHFT1 — Shift FR1 Right/Increment Exponent
*
*
ON ENTRY A
DC 3 A
*
RSHFT0
DC 3 A
A2D4
LDX
#FR0
DC3C
D002
"DC40
BNE
:RSH
DC3E
RSHFT1
DC3E
A2E0
LDX
#FR1
DC40
:RSH
DC40
86F9
STX
ZTEMP3
DC42
85F7
STA
ZTEMP4
DC44
85F8
STA
ZTEMP4+1
DC46
:RSH2
DC46
A004
LDY
#FMPREC-1
DC48
:RSH1
DC48
B504
LDA
4,X
DC 4 A
9505
STA
5,X
DC4C
CA
DEX
DC4D
88
DEY
DC4E
D0F8
"DC48
BNE
:RSH1
DC50
A900
LDA
#0
DC52
9505
STA
5,X
DC 54
A6F9
LDX
ZTEMP3
DC 56
C6F7
DEC
ZTEMP4
DC 58
D0EC
"DC46
BNE
:RSH2
FIX EXPONENT
DC 5 A
B500
LDA
0,X
DC5C
18
CLC
DC5D
65F8
ADC
ZTEMP4+1
DC5F
9500
STA
0,X
DC61
60
RTS
A - # OF PLACES TO SHIFT
POINT TO FR0
POINT TO FR1
SAVE FR POINTER
SAVE # OF BYTES TO SHIFT
SAVE FOR LATER
GET # OF BYTES TO MOVE
GET CHAR
STORE CHAR
POINT TO NEXT BYTE
DEC LOOP CONTROL
IF MORE TO MOVE, DO IT
GET 1ST BYTE
STORE IT
GET FR POINTER
DO WE NEED TO SHIFT AGAIN?
IF YES, DO IT
GET EXPONENT
SUB # OF SHIFTS
SAVE NEW EXPONENT
RSHFOE — Shift FRO/FRE 1 Byte Right [They Are Contiguous]
DC62
RSHF0E
DC62
A20A
LDX
#FMPREC*2
DC64
:NXTB1
DC64
B5D4
LDA
FR0.X
DC66
95D5
STA
FR0+1,X
DC68
CA
DEX
DC69
10F9
"DC64
BPL
:NXTB1
DC6B
A900
LDA
#0
DC6D
85D4
STA
FR0
DC6F
60
RTS
GET LOOP CONTROL
GET A BYTE
MOVE IT OVER 1
DEC COUNTER
MOVE NEXT BYTE
GET ZERO
SHIFT IT IN
:CVFR0 — Convert Each Byte in FRO to 2 Characters in LBUFF
*
ON
ENTRY
*
*
DC70
:CVFR0
DC70
85F7
STA
ZTEMP4
DC72
A200
LDX
#0
DC74
A000
LDY
#0
DECIMAL POINT POSITION
SAVE DECIMAL POSITION
SET INDEX INTO FR0M
SET INDEX INTO OUTPUT
LINE [LBUFF]
CONVERT A BYTE
263
Source Code
DC76
:CVBYTE
DC76
2033DC
JSR
:TSTDP
; PUT IN D.P. NOW?
DC79
:CVB1
DC79
38
SEC
; DECREMENT DECIMAL
DC 7 A
E901
SBC
#1
; X
DC7C
85F7
STA
; DO
ZTEMP4
1ST DIGIT
; SAVE IT
DC7E
B5D5
LDA
FR0M.X
; GET FROM FR0
DC 80
LSRA
; SHIFT OUT LOW ORDE
DC80
+4A
LSR
A
DC81
LSRA
; TO GET 1ST DIGIT
DC81
+4A
LSR
A
DC82
LSRA
; X
DC82
+4A
LSR
A
DC83
LSRA
; x
DC83
+4 A
LSR
A
DC84
209DDC
JSR
:STNUM
; GO PUT f IN BUFFER
DO SECOND DIGIT
DC87
B5D5
LDA
FR0M,X
DC89
290F
AND
I50F
DC8B
209DDC
JSR
:STNUM
DC8E
E8
INX
DC8F
E005
CPX
#FMPREC
DC91
90E3 "DC76
BCC
:CVBYTE
PUT IN DECK
DC93
TSTDP
DC93
A5F7
LDA
ZTEMP4
DC95
D005 ~DC9C
BNE
:TST1
DC97
A92E
LDA
#' . '
DC99
209FDC
JSR
:STCHAR
DC9C
TST1
DC9C
60
RTS
:STNUM — Put ASCII
Numbei
in
LBUFF
h
ON
ENTRY
; GET NUMBER FROM FR0
; AND OUT HIGH ORDER BITS
; GO PUT # IN BUFFER
; INCR FR0 POINTER
; DONE LAST FR0 BYTE?
; IF NOT, MORE TO DO
GET DECIMAL POSITION
IF NOT = RTN
GET ASCII DECIMAL POINT
PUT D.P. IN BUFFER
A - DIGIT TO BE CONVERTED TO ASCII
AND PUT IN LBUFF
Y - INDEX IN LBUFF
:STCHAR — Store Character in A in LBUFF
DC9D
: STNUM
DC9D
0930
ORA
DC9F
:STCHAR
DC9F
998005
STA
DC A 2
C8
I NY
DC A 3
60
RTS
#?30
CONVERT TO ASCII
PUT IN LBUFF
INCR LBUFF POINTER
:FNZER0 — Find Last Non-zero Character in LBUFF
* ON
EXIT
A
*
X
*
DCA4
:FNZER0
DC A 4
A20A
LDX
#10
DC A 6
:FN3
DCA6
BD8005
LDA
LBUFF
X
DC A 9
C92E
CMP
#' . '
DCAB
F007 "DCB4
BEQ
:FN1
DCAD
C930
CMP
#'0'
DCAF
D007 "DCB8
BNE
:FN2
DCB1
CA
DEX
DCB2
D0F2 "DCA6
BNE
:FN3
LAST CHAR
POINT TO LAST CHAR
POINT TO LAST CHAR IN LBUFF
GET THE CHARACTER
IS IT DECIMAL?
IF YES, BR
IS IT ZERO?
IF NOT, BR
DECREMENT INDEX
UNCONDITIONAL BR
264
Source Code
DCB4
:FN1
DCB4
CA
DEX
DCB5
BD8005
LDA
LBUFF,X
DCB8
:FN2
DCBS
60
RTS
:GETDIG — Get Next Digit from FRO
DCB9
DCB9
20EBDB
DCBC
A5EC
DCBE
290F
DCC0
60
:DECINB — D«
DCCl
DCC1
38
DCC2
A5F3
DCC4
E901
DCC6
85F3
DCC8
A5F4
DCCA
E900
DCCC
85F4
DCCE
60
*
ON
ENTRY FR0 - 1
*
*
ON
EXIT A - DIGIT
*
:GETDIG
JSR
NIBSH0
LDA
FRX
AND
#50F
RTS
ntlNBUFF
: DECINB
SEC
LDA
INBUFF
SBC
#1
STA
INBUFF
LDA
INBUFF+1
SBC
#0
STA
IH8UFF+1
RTS
DECREMENT BUFFER INDEX
GET LAST CHAR
SHIFT FR0 LEFT ONE NIBBLE
GET BYTE CONTAINING
SHIFTED NIBBLE
AND OUT HIGH ORDER NIBBLE
SUBTRACT ONE FROM INBUFF
X
X
X
X
X
X
MDESUP — Common Set-up for Multiply and Divide Exponent
* ON EXIT
FR1 - FR1 EXP WITH OUT SIGN
A - FR0 EXP WITHOUT SIGN
FRSIGN - SIGN FOR QUOTIENT
DCCF
MDESUP
DCCF
A5D4
LDA
FR0 J
DCD1
45E0
EOR
FR1 ;
DCD3
2980
AND
#$80
DCD5
85EE
STA
FRSIGN ;
DCD7
06E0
ASL
FR1 ;
DCD9
46E0
LSR
FR1 ;
DCDB
A5D4
LDA
FR0 ;
DCDD
297F
AND
#$7F ;
DCDF
60
RTS
GET FR0 EXPONENT
GET FR1 EXPONENT
AND OUT ALL BUT SIGN BIT
SAVE SIGN
SHIFT OUT SIGN IN FR1 EXP
RESTORE FR1 EXP WITHOUT SIGN
GET FR0 EXP
AND OUT SIGN BIT
MDSUP — Common Set-up for Multiply and Divide
+
*
ON
ENTRY
DCE0
MDSUP
DCE0
05EE
ORA
FRSIGN
DCE2
85ED
STA
EEXP
DCE4
A900
LDA
#0
DCE6
85D4
STA
FR0
DCE8
85E0
STA
FR1
DCEA
2028DD
JSR
MVFR12
DCED
20E7DB
JSR
NIBSH2
DCF0
A5EC
LDA
FRX
A - EXPONENT
CC - SET BY ADD OR SUB TO GET A
OR IN SIGN BIT
SAVE EXPONENT FOR LATER
CLEAR A
CLEAR FR0 EXP
CLEAR FR0 EXP
MOVE FR1 TO FR2
; SHIFT FR2 1 NIBBLE LEFT
; GET SHIFTED NIBBLE
265
Source Code
DCF2 290F
DCF4 85E6
DCF6 A905
DCF8 85F5
DCFA 2034DD
DCFD 2044DA
AND
#$0F
STA
FR2
LDA
#FMPREC
STA
ZTEMP1
JSR
MVFR0E
JSR
ZFR0
; AND OUT HIGH ORDER NIBBLE
; STORE TO FINISH SHIFT
SET LOOP CONTROL
X
MOVE FR0 TO FRE
CLEAR FR0
FRA
FRA10 - ADD FR1 TO FR0 [6 BYTES]
FRA20 - ADD FR2 TO FR0 [6 BYTES]
FRA1E - ADD FR1 TO FRE
FRA2E - ADD FR2 TO FRE
DD01
FRA10
DD01
A2D9
LDX
#FR0+FMPREC
DD03
D006
"DD0B
BNE
:F1
DD05
FRA20
DD05
A2D9
LDX
#FR0+FMPREC
DD07
D008
'DD11
BNE
:F2
DD09
FRA1E
DD09
A2DF
LDX
#FRE+FMPREC
DD0B
:F1
DD0B
A0E5
LDY
#FR1+FMPREC
DD0D
D004
~DD13
BNE
:FRA
DD0F
FRA2E
DD0F
A2DF
LDX
#FRE+FMPREC
DD11
:F2
DD11
A0EB
LDY
#FR2+FMPREC
DD13
:FRA
DD13
A905
LDA
#FMPREC
DD15
85F7
STA
ZTEMP4
DD17
18
CLC
DD18
F8
SED
DD19
:FRA1
DD19
B500
LDA
0,X
DD1B
790000
ADC
0,Y
DD1E
9500
STA
0,X
DD20
CA
DEX
DD21
88
DEY
DD22
C6F7
DEC
ZTEMP4
DD24
10F3
~DD19
BPL
:FRA1
DD26
D8
CLD
DD27
60
RTS
POINT TO LAST BYTE OF SUM
GET VALUE FOR LOOP CONTROL
SET LOOP CONTROL
CLEAR CARRY
SET DECIMAL MODE
GET 1ST BYTE OF
ADD
STORE
POINT TO NEXT BYTE
POINT TO NEXT BYTE
DEC COUNTER
IF MORE TO DO, DO IT
CLEAR DECIMAL MODE
MVFR12 — Move FR1 to FR2
DD28
MVFR12
DD28
A005
LDY
#FMPREC
DD2A
:MV2
DD2A
B9E000
LDA
FR1, Y
DD2D
99E600
STA
FR2, Y
DD30
88
DEY
DD31
10F7 "DD2A
BPL
:MV2
DD33
60
RTS
SET COUNTER
GET A BYTE
STORE IT
DEC COUNTER
IF MORE TO MOVE,
266
Source Code
MVFROE — Move FRO to FRE
DD34
MVFR0E
DD34
A00 5
LDY
#FMPREC
DD36
:MV1
DD36
B9D400
LDA
FRB, Y
DD39
99DA00
STA
FRE, Y
DD3C
88
DEY
DD3D
10F7 "DD36
BPL
:MV1
DD3F
60
RTS
Polynomial Evaluation
DD40
DD42
DD44
DD46
DD48
DD4A
DD4D
DD50
DD52
DD54
DD57
DD59
DD5B
DD5E
DD60
DD61
DD63
DD65
DD67
DD69
DD6B
DD6D
DD6F
DD71
DD73
DD76
DD79
DD7B
DD7D
DD7F
DD81
DD83
DD86
DD88
86FE
84FF
85EF
A2E0
A005
20A7DD
20B6DD
A6FE
A4FF
2089DD
C6EF
F02D "DD88
20DBDA
B028 "DD88
18
A5FE
6906
85FE
9006 "DD6F
A5FF
6900
85FF
A6FE
A4FF
2098DD
2066DA
B00D "DD88
C6EF
F009 "DD88
A2E0
A005
2098DD
30D3 "DD5B
60
PLYEVL
STY
STA
LDX
LDY
JSR
JSR
LDX
LDY
JSR
DEC
BEQ
PLYEV1
BCS
CLC
LDA
ADC
STA
BCC
LDA
ADC
STA
PLYEV2
LDY
JSR
JSR
BCS
DEC
BEQ
LDX
LDY
JSR
BMI
PLYOUT
Y=A[0]+A[1]*X+A[2]*X**2+. . . +A[N]*X**N, N>0
=[[■ - . [A[N]*X+A[N-1]]*X+. . .+A[2]]*X+A[1]]*X+A[0]
INPUT: X IN FR0, N+l IN A-REG
REG [X, Y]->A[N]. . .A[0]
OUTPUT Y IN FR0
USES FPTR2, PLYCNT, PLYARG
CALLS FST0R, FMOVE, FLD1R, FADD, FMUL
STX FPTR2 ;SAVE POINTER TO COEFF ' S
FPTR2+1
PLYCNT
#PLYARG&$FF
#PLYARG/$100
FST0R ,-SAVE ARG
FMOVE ;ARG->FR1
FPTR2
FPTR2+1
FLD0R
PLYCNT
PLYOUT
JSR FMUL
PLYOUT
FPTR2
#FPREC
FPTR2
PLYEV2
FPTR2+1
#0
FPTR2+1
FPTR2
FPTR2+1
FLD1R
FADD
PLYOUT
PLYCNT
PLYOUT
#PLYARG&$FF
#PLYARG/?100
FLD1R
PLYEV1
;COEF->FR0 [INIT SUM]
DONE ?
SUM * ARG
' FLOW
;BUMP COEF POINTER
; ACROSS PAGE
GET NEXT COEF
SUM*ARG + COEF
' FLOW
rDONE ?
;GET ARG AGAIN
; [=JMP]
Floating Load/Store
*
LOAD FR0 FROM [X,Y]
X=LSB, Y=MSB,
USES FLPTR [PG0]
DD89
86FC
FLD0R
STX FLPTR
; SET FLPTR =>
[X,Y]
DD8B
84FD
STY
FLPTR+1
DD8D
A005
FLD0P
LDY #FPREC-1
; # BYTES ENTER
HERE W/FLPTR SET
DD8F
B1FC
FLD01
LDA [FLPTR], Y
; MOVE
DD91
99D400
STA
FR0, Y
DD94
88
DEY
DD95
10F8 *
DD8F
BPL
FLD01
; COUNT S, LOOP
DD97
60
RTS
*
*
LOAD FR1 FROM [X,Y]
OR [FLPTR]
DD98
86FC
FLD1R
STX FLPTR
; FLPTR=>[X,Y]
267
Source Code
DD9A
84FD
STY
FLPTR+1
DD9C
A005
FLD1P
LDY
#FPREC-1
DD9E
B1FC
FLD11
LDA
[FLPTR], Y
DDA0
99E000
STA
FR1, Y
DDA3
88
DEY
DDA4
10F8 *
DD9E
BPL
FLD11
DDA6
60
RTS
•
STORE FR0 IN [X,Y
DDA7
86FC
FST0R
STX
FLPTR
DDA9
84FD
STY
FLPTR+1
DDAB
A005
FST0P
LDY
#FPREC-1
DDAD
B9D400
FST01
LDA
FR0, Y
DDB0
91FC
STA
[FLPTR], Y
DDB2
88
DEY
DDB3
10F8 "
DDAD
BPL
FST01
DDB5
60
RTS
; # BYTES ENTER W/FLPTR SET
; MOVE
COUNT 5, LOOP
ENTRY W/FLPTR SET
MOVE FR0 TO FR1
DDB6
MV0TO1
DDB6
A205
FMOVE
LDX
#FPREC-1
DDB8
B5D4
FMOVE1
LDA
FR0.X
DDBA
95E0
STA
FR1.X
DDBC
CA
DEX
DDBD
10F9
*DDB8
BPL
FMOVE 1
DDBF
60
RTS
EXP[X] and EXP10[X]
DDC0
A289
EXP
LDX
#LOG10ES.$FF
; E**X = 10**[X*LOG10[E]]
DDC2
A0DE
LDY
#LOG10E/$100
DDC4
2098DD
JSR
FLD1R
DDC7
20DBDA
JSR
FMUL
DDCA
B07F "DE4B
BCS
EXPERR
DDCC
A900
EXP 10
LDA
#0
; 10**X
DDCE
85F1
STA
XFMFLG
; CLEAR TRANSFORM FLAG
DDD0
A5D4
LDA
FR0
DDD2
85F0
STA
SGNFLG
; REMEMBER ARG SGN
DDD4
297F
AND
#$7F
; ; & MAKE PLUS
DDD6
85D4
STA
FR0
DDD8
38
SEC
DDD9
E940
SBC
#?40
DDDB
3026 "DE03
BMI
EXP1
; X<1 SO USE SERIES DIRECTLY
*
10**X = 10**[I+F] =
[10**1] * [10**F]
DDDD
C904
CMP
#FPREC-2
DDDF
106A "DE4B
BPL
EXPERR
; ARG TOO BIG
DDE1
A2E6
LDX
#FPSCR&$FF
DDE 3
A005
LDY
#FPSCR/$100
DDE5
20A7DD
JSR
FST0R
; SAVE ARG
DDE 8
20D2D9
JSR
FPI
; MAKE INTEGER
DDEB
A5D4
LDA
FR0
DDED
85F1
STA
XFMFLG
; SAVE MULTIPLIER EXP IN XFORM
DDEF
A5D5
LDA
FR0+1
; CHECK MSB
DDF1
D058 "DE4B
BNE
EXPERR
; SHOULD HAVE NONE
DDF3
20AAD9
JSR
IFP
; NOW TURN IT BACK TO FLPT
DDF6
20B6DD
JSR
FMOVE
DDF9
A2E6
LDX
#FPSCR&$FF
DDFB
A005
LDY
KFPSCR/S100
DDFD
2089DD
JSR
FLD0R
; GET ARG BACK
DE00
2060DA
JSR
FSUB
r ARG - INTEGER PART = FRACTIO
*
NOW
HAVE FRACTION PART OF ARG [F] IN FR0,
*
INTEGER PART [I]
*
IN
XFMFLG. USE SERIES APPROX FOR
*
10*
*F, THEN MULTIPLY
' BY 10**1
DE03
EXP1
DE03
A90A
LDA
SNPCOEF
DE05
A24D
LDX
#P10COF6,$FF
DE07
A0DE
LDY
#P10COF/$100
268
Source Code
DE09
DE0C
DE0F
DE12
DE14
DE16
DE17
DE17
DE18
DE1A
DE1C
DE1E
DE20
DE22
DE24
DE26
DE28
DE29
DE2B
DE2D
DE2E
DE30
DE32
DE34
DE36
DE39
DE3B
DE3D
DE40
DE42
DE44
DE47
DE4A
DE4B
DE4C
DE4D
DE53
DE59
DE5F
DE65
DE6B
DE71
DE77
DE7D
DE83
DE89
DE8F
~DE4B
"DE4B
2040DD
20B6DD
20DBDA
A5F1
F023 "DE39
18
+6A
85E0
A901
9002 "DE20
A910
85E1
A204
A900
95E2
CA
10FB "DE26
A5E0
18
6940
B019
3017
85E0
20DBDA
A5F0
100D *DE4A
20B6DD
A28F
A0DE
2089DD
2028DB
60
38
60
3D17941900
00
3D57330500
00
3E05547662
00
3E32196227
00
3F01686030
36
3F07320327
41
3F25433456
75
3F66273730
50
4001151292
55
3F99999999
99
= 000A
3F43429448
19
4001000000
00
JSR
PLYEVL
JSR
FMOVE
JSR
FMUL
LDA
XFMFLG
BEQ
EXPSGN
CLC
RORA
ROR
A
STA
FR1
LDA
#1
BCC
EXP2
LDA
#510
EXP2 STA FR1+1
LDX IFPREC-2
LDA #0
EXP3 STA FR1+2.X
DEX
BPL
LDA
CLC
ADC
BCS
BMI
STA
JSR
EXPSGN LDA
EXP 3
FR1
#540
EXPERR
EXPERR
FR1
FMUL
SGNFLG
,-P[X]
;P[X]*P[X]
; DID WE TRANSFORM ARG
,- NO SO LEAVE RESULT ALONE
; 1/2
; SAVE AS EXP-TO-BE
; GET MANTISSA BYTE
; CHECK BIT SHIFTED OUT OF A
; I WAS ODD - MANTISSA = 10
CLEAR REST OF MANTISSA
BACK TO EXPONENT
BIAS IT
OOPS. . . IT'S TOO BIG
FR1 = 10**1
[10**IJ*[10**F:
WAS ARG<0
NO-DONE
YES-INVERT RESULT
BPL EXPOUT
JSR FMOVE
LDX #FONE&5FF
LDY #FONE/5100
JSR FLD0R
JSR FDIV
EXPOUT RTS
EXPERR SEC
RTS
P10COF .BYTE 53D, 517, 594, 519,0,0 ; 0. 00001 79419
.BYTE 53D, 557, 533, 505, 0, ,-0.0000573305
.BYTE 53E, 505, 554, 576, 562,0 ; . 0005547662
.BYTE 53E, 532, 519, 562, 527, ,- Z
.BYTE 53F, 501, 568, 560,530,536
.BYTE 53F, 507, 532, 503, 527, 541
.BYTE 53F, 525, 543, 534,556,575
.BYTE 53F, 566, 527, $37, 530, 550
.BYTE 540,501,515,512,592,555
.BYTE 53F, 599, 599, 599, 599, 599
[PANT, PANT - FINISHED::]
FLAG ERROR
5, QUIT
0032176227
0.0168603036
0.0732032741
0.2543345675
0.6627373050
1.15129255
0.999999999
NPCOEF
LOG10E
EQU
. BYTE
(*-P10COF)/FPREC
53F, 543, 542, $94, 548, 519
LOG10[E]
.BYTE 540,1,0,1
Z a [X-C]/[X + C]
DE95
86FE
XFORM STX FPTR2
DE97
84FF
STY
FPTR2+1
DE99
A2E0
LDX
#PLYARG£,5FF
DE9B
A005
LDY
#PLYARG/5100
DE9D
20A7DD
JSR
FST0R
DEA0
A6FE
LDX
FPTR2
DEA2
A4FF
LDY
FPTR2+1
; STASH X IN PLYARG
269
Source Code
DEA4
DEA7
DEAA
DEAC
DEAE
DEB1
DEB3
DEB 5
DEB8
DEBA
DEBC
DEBF
DEC 2
DEC4
DEC 6
DEC 9
DECC
2098DD
2066DA
A2E6
A005
20A7DD
A2E0
A005
2089DD
A6FE
A4FF
2098DD
2060DA
A2E6
A005
2098DD
2028DB
60
JSR
JSR
LDX
LDY
JSR
LDX
LDY
JSR
LDX
LDY
JSR
JSR
LDX
LDY
JSR
JSR
RTS
FLD1R
FADD
#FPSCR6,$FF
#FPSCR/$100
FST0R
#PLYARGS,$FF
#PLYARG/$100
FLD0R
FPTR2
FPTR2+1
FLD1R
FSUB
#FPSCR5,$FF
#FPSCR/$100
FLD1R
FDIV
[X-C]/[X+C] = Z
LOG10[X]
DECD
A901
DECF
D002 "I
DED1
A900
DED3
85F0
DED5
A5D4
DED7
1002 "I
DED9
38
DEDA
60
DEDB
DEDB
A5D4
DEDD
85E0
DEDF
38
DEE0
E940
DEE 2
DEE 2
+0A
DEE 3
85F1
DEE5
A5D5
DEE 7
29F0
DEE 9
D004 "I
DEEB
A901
DEED
D004 "I
DEEF
E6F1
DEF1
A910
DEF3
85E1
DEF5
A204
DEF7
A900
DEF9
95E2
DEFB
CA
DEFC
10FB "1
DEFE
2028DB
DF01
DF01
A266
DF03
A0DF
DF05
2095DE
DF08
A2E6
DF0A
A005
DF0C
20A7DD
DF0F
20B6DD
DF12
20DBDA
DF15
A90A
DF17
A272
DF19
A0DF
DF1B
2040DD
DF1E
A2E6
DF20
A005
DF22
2098DD
LOG LDA # 1
BNE LOGBTH
LOG10 LDA #0
LOGBTH STA SGNFLG
; REMEMBER ENTRY POINT
; CLEAR FLAG
; USE SGNFLG FOR LOG/LOG10
MARKER
LDA
FR0
BPL
LOG 5
LOGERR
SEC
RTS
LOG 5
WE WANT X
10**Y HAS SAME EXP
S, MANTISSA BYTE
F*[10**Y], 1<F<10
BYTE AS X
1 OR 10
LDA
FRO
STA
FR1
SEC
SBC
#$40
AS LA
ASL
A
STA
XFMFLG
; REMEMBER Y
LDA
FR0+1
AND
#$F0
BNE
LOG 2
LDA
#1
BNE
LOG 3
LOG 2
INC
XFMFLG
; BUMP Y
LDA
#$10
LOG3
STA
FR1+1
; SET UP MANTISSA
LDX
#FPREC-2
; CLEAR REST OF MANTIS
LDA
#0
LOG4
STA
FR1+2.X
DEX
BPL
LOG 4
JSR
FDIV
; X = X/tl0**Y] - S.B.
IN [1, 10]
FLOG10
; ;LOG10[X], 1<=X<=10
LDX
#SQR10&$FF
LDY
#SQR10/$100
JSR
XFORM
,-Z = [X-C]/[X+C],C*C =
LDX
#FPSCR&$FF
LDY
#FPSCR/$100
JSR
FST0R
;SAVE Z
JSR
FMOVE
JSR
FMUL
; Z*Z
LDA
#NLCOEF
LDX
#LGCOEPS,$FF
LDY
#LGCOEF/$100
JSR
PLYEVL
; P[Z*Z]
LDX
#FPSCR£.$FF
LDY
#FPSCR/$100
JSR
FLD1R
270
Source Code
*)
DF25
DF28
DF2A
DF2C
DF2F
DF32
DF35
DF37
DF39
DF3B
DF3D
DF3F
DF41
DF42
DF44
DF46
DF46
DF49
DF4B
DF4D
DF4F
DF51
DF53
DF53
DF56
DF56
DF58
DF5A
DF5C
DF5E
DF61
DF64
DF65
DF66
DF6C
DF72
DF78
DF7E
DF84
DF8A
DF90
DF96
DF9C
DFA2
DFA8
DFAE
DFB4
DFBA
DFC0
DFC6
DFCC
DFD2
20DBDA
A26C
A0DF
2098DD
2066DA
20B6DD
A900
85D5
A5F1
85D4
1007 "DF46
49FF
18
6901
85D4
20AAD9
24F1
1006 "DF53
A980
05D4
85D4
2066DA
A5F0
F00A "DF64
A289
A0DE
2098DD
2028DB
18
60
4003162277
66
3F50000000
00
3F49155711
08
BF51704947
08
3F39205761
95
BF04396303
55
3F10093012
64
3F09390804
60
3F12425847
42
3F17371206
08
3F28952971
17
3F86858896
44
= 000A
3E16054449
00
BE95683845
00
3F02687994
16
BF04927890
80
3F07031520
00
BF08922912
44
3F11084009
11
JSR
LDX
LDY
JSR
JSR
JSR
LDA
STA
LDA
STA
BPL
EOR
CLC
ADC
STA
LOG 6
JSR
BIT
BPL
LDA
ORA
STA
LOG 7
JSR
LOGOUT
LDA
BEQ
LDX
LDY
JSR
JSR
LOGDON CLC
RTS
SQR10 .BYTE
FMUL
#FHALF£,$FF
#FHALF/$100
FLD1R
FADD
FMOVE
#0
FR0+1
XFMFLG
FR0
LOG6
#-1
#1
FR0
IFP
XFMFLG
LOG7
#580
FR0
FR0
FADD
SGNFLG
LOGDON
SLOG10E&255
#LOG10E/?100
FLD1R
FDIV
; Z*P[Z*Z]
0.5 + Z*P[Z*Z]
FLIP SIGN
LEAVES FR1 ALONE
FLIP AGAIN
LOG[X] = LOG[X] +Y
,-WAS LOG10, NOT LOG
; LOG[X]/LOG10[E]
$40, $03, $16, $22, $77, $66 ;SQUARE ROOT OF 10
FHALF .BYTE ?3F, $50, 0, 0, 0, ; 0.5
LGCOEF .BYTE $3F , $49 , $1 5 , $5 7 , $1 1 , $08 ; . 4915571108
.BYTE $BF, $51, $70, $49, $47, $08
.BYTE $3F, $39, $20, $57, $61, $95
.BYTE $BF, $04, $39, $63, $03, $55
.BYTE $3F, $10, $09, $30, $12, $64
.BYTE $3F, $09, $39, $08, $04, $60
.BYTE $3F, $12, $42, $58, $47, $42
.BYTE $3F, $17, $37, $12, $06, $08
.BYTE ?3F, $28, $95, $29, $71, $17
.BYTE
-0.5170494708
J. 3920576195
-0.0439630355
3. 1009301264
| 0.0939080460
). 1242584742
; 0.1737120608
(.28957117
$3F, $86, $8 5, $88, $96, $44 ; . 8685889644
NLCOEF EQU
ATCOEF .BYTE
(*-LGCOEF)/FPREC
$3E, $16, $05, $44, $49, (
0016054449
.BYTE $BE, $95, $68, $38, $45,0 ; -0 . 009568345
.BYTE $3F, $02, $68, $79, $94, $16 ; . 0268799416
.BYTE $BF, $04, $92, $78, $90, $80 ; -0 . 0492789080
.BYTE $3F, $07, $03, $15, $20, ; . 07031 52000
.BYTE $BF, $08, $92, $29, $12, $44 ; -0 . 0892291 244
.BYTE $3F, $11, $08, $40, $09, $11 ; 0. 1 10840091 1
271
Source Code
.BYTE $BF, $14, $28, $31, 556, $04 ,--0.1428315604
.BYTE $3F, $19, $99, $98, $77, $44 ,-0.1999987744
.BYTE $BF, $33, $33, $33, $31, $13 ; -0.3333333113
DFD8 BF14283156
04
DFDE 3F19999877
44
DFE4 BF33333331
13
DFEA 3F99999999 FP9S .BYTE $3F, $99, $99 , $99, $99 , $99 ; 0.999999999
99
= 000B NATCF EQU ( *-ATCOEF) /FPREC
DFF0 3F78539816 PI0V4 .BYTE $3F, $78 , $53, $98, $16, $34 ,- Pi/4 = ARCTAN[1.0]
34
Atari Cartridge Vectors
DFF6
= BFF9
ORG
CRTGI
BFF9
SCVECT
BFF9
60
RTS
BFFA
00A0
DW
COLDS
BFFC
00
DB
BFFD
05
DB
5
BFFE
F9BF
DW
SCVEC
; COLDSTART ADDR
; CART EXISTS
; FLAG
COLDSTART ENTRY ADDR
C000
End of BASIC
272
Appendix A
Macros in
Source Code
The following is a listing of the macros used in this source listing. You will
be able to tell when a macro was used by a plus ( + ) sign to the left of the hex
code produced in column two by the assembler.
ASLA: MACRO
%L ASL A
ENDM
RORA: MACRO
%L ROR A
ENDM
LSRA: MACRO
%L LSR A
ENDM
ROLA: MACRO
%L ROL A
ENDM
FDB: MACRO
%L DW REV (%1)
IF '=%2' <> '='
DW REV (%2)
IF l =%3 ' <>
DW REV (%3)
IF '=14' <> '='
DW REV (%4)
IF '=S5 <> '='
DW REV (%5)
ENDIF
ENDIF
ENDIF
ENDIF
ENDM
LOCAL: MACRO
PROC
ENDM
BYTE: MACRO
IF '%1 ' = '='
%L DB $80+( ( (%2-*)S,?7F) XOR $40 )
ELSE
IF '%!' = '08'
%L DW ( %2 )
ELSE
%L DB %1
ENDIF
ENDIF
ENDM
Syntax Table Macro
THIS MACRO IS USED TO SIMULATE THE ACTION OF THE ORIGINAL
ASSEMBLER IN HANDLING SPECIAL SYNTAX TABLE PSEUDO OPS AND
OPERANDS
THE 'SYN' MACRO EXAMINES UP TO 4 ARGUMENTS FOR CERTAIN SPECIAL
CASE NAMES.
IF THE NAME 'JS' IS FOUND, IT GENERATES A SPECIAL 'RELATIVE
SYNTAX JSR' TO THE LABEL FOUND IN THE NEXT PARAMETER
273
Appendix A
; IF THE NAME 'AD' IS FOUND, IT GENERATES A WORD ADDRESS OF
; THE LABEL FOUND IN THE NEXT PARAMETER
; ANY OTHER NAME IS ASSUMED TO BE A SIMPLE BYTE VALUE
SYN: MACRO
:SYAR2 SET '=«%2'<>' = '
:SYAR3 SET '=%3 '<>'='
:SYAR4 SET '=%4 '<>'='
IF '%1' = 'JS'
%L DB $80+( ( (»2-*)&$7F) XOR $40 )
:SYAR2 SET
ELSE
IF '%1' = 'AD'
%L DW (%2)
:SYAR2 SET
ELSE
%L DB %1
ENDIF
ENDIF
IF :SYAR2
IF '%2' = 'JS'
DB $80+( ( (%3-*)&$7F) XOR $40 )
:SYAR3 SET
ELSE
IF '%2' = 'AD'
DW (%3)
:SYAR3 SET
ELSE
DB %2
ENDIF
ENDIF
ENDIF
IF :SYAR3
IF ' %3 ' = ' JS '
DB $80+( ( (%4-*)&?7F) XOR $40 )
:SYAR4 SET
ELSE
IF '%3' = 'AD'
DW (%4)
:SYAR4 SET
ELSE
DB %3
ENDIF
ENDIF
ENDIF
IF :SYAR4
IF '%4' = 'JS'
DB $80+( ( (%5-*)&$7F) XOR $40 )
ELSE
IF '%4' = 'AD'
DW (%5)
ELSE
DB %4
ENDIF
ENDIF
ENDIF
ENDM
274
Appendix B
The Bugs in
Atari BASIC
Yes, it's true. There are some bugs in Atari BASIC. Of course,
that's not surprising, since Atari released the product as ROM
without giving the authors a chance to do second-round bug-
fixing. But what hurts, a little, is that most of the fixes for the
bugs have been known since June of 1979.
As this book is being written, rumor has it that at last Atari
is in the final stages of releasing a new version of the BASIC
ROMs. Unfortunately, these modified ROMs will appear too
late for us to comment upon them in this edition. On the other
hand, there are supposed to be fewer than twenty fixes
implemented (which isn't a bad record for a product as mature
as Atari BASIC), so those of you who are willing to PEEK
around a bit can use this listing as at least a road map to the
new ROMs.
In any case, though, we thought it would be appropriate to
mention a few of the bugs we know about, show you why they
exist, and tell how we fixed them back there in the summer of
'79.
The Editing and String Bug
In the course of editing a BASIC program, sometimes the
system loses all or part of the program, or it simply hangs.
Often, even SYSTEM RESET will not return control to the user.
Also, string assignments that involve the movement of
exact multiples of 256 bytes do not move the bytes properly.
For example, A$ = B$(257,512) would actually move bytes 513
through 768 of B$ into bytes 257 through 512 of A$, even if
neither string were DIMensioned to those values.
Both of these are really the same bug. And both are caused
because we strove to be a little too efficient.
There are many ways to move strings of bytes using the
6502's instruction set. The simplest and most-used methods,
though, are excruciatingly slow. So Paul and Kathleen
invented a super-fast set of move-memory routines, one for
275
Appendix B
moving up in memory (EXPAND, at $A881) and one for
moving down in memory (CONTRACT, at $A8FD).
Unfortunately, the routines are very complex (which is what
makes them fast) and difficult to interface with properly. And
so a bug crept into CONTRACT.
Take a look at the code of FMOVER ($A947). When we get
here, we expect MVLNG to contain the complement of the least
significant byte of the move length while MVLNG + 1 contains
its most significant byte. But look what happens if the original
move length was, for example, $200. The complement of the
least significant byte ($00) is still zero ($00), so the BEQ to
:CONT4 occurs immediately.
But by then, the X register contains the number of pages to
move plus one (X would contain 3 in this example), so we
increment it (it becomes 2) and go to label :CONT3, where we
bump the high-order byte of both the source and destination
addresses. Ah, but therein lies the rub! We haven't yet done
anything with the first values in those source and destination
addresses, so we have effectively skipped 256 bytes of each!
The solution is to replace the BEQ :CONT4 at $A94E with
the following code:
DEX
BNE :CONT2
RTS
Do you see the difference? If we enter with MVLNG equal
to zero, we immediately move 256 bytes (at :CONT2) before ever
attempting to change the source and destination addresses.
And this fix works, honest. We've been using it like this for
over two years in BASIC A + .
Minus Zero
Taking the unary minus of a number (A = : PRINT -A) can
result in garbage. Usually, this garbage will not affect
subsequent calculations, but it does print strangely. And how
did this come about?
We simply forgot to take into consideration the fact that
zero doesn't really have a sign. Look at the code for the unary
minus operator (XPUMINUS, at $ACA8). Do you see the
problem? We simply invert the most significant bit (the sign bit)
of the floating point number in FRO.
276
Appendix B
What we should have coded would be something like this:
LDA FRO
BEQ :NOINVERT
EOR #$80
STA FRO
:NOINVERT
Luckily, this is not too severe a problem to the BASIC user
(one can always use "PRINT 0-A" instead of "PRINT -A"),
but just think — it only cost two bytes to fix this bug.
LOCATE and GET
The GET statement does not reinitialize its buffer pointer, so it
can do nasty things to memory if used directly after a statement
which has changed the system buffer pointer. For example,
GET can change the line number of a DATA statement if it is
used after a READ. Also, the same problem exists for the
LOCATE statement, since it calls GET.
From BASIC, the easiest solution is to use a function or
statement which is known to reset the pointer. Coding
"XX = STR$(0)" works just fine, as does PRINTing any
number.
Within the source listing, the problem exists at location
$BC82, label GET1. If the code had simply read as follows,
there would be no bug:
GET1
JSR INTLBF ; reset buffer pointer
LDA #ICGTC ; continue as before
INPUT and READ
Using either an INPUT or READ statement without a following
variable does not cause a syntax error (as it should). Then,
attempting to execute a statement such as 20 INPUT can cause
total system lock-up.
The solution from BASIC? Be careful and don't do it.
And this is one bug that we will not show the fix for,
simply because it's too long and involved. We will, however,
point to labels :SINPUT and :SREAD (at locations $A6F4 and
$A6F5) in the Syntax Tables and show why the bug exists.
Note that the :SINPUT does a syntax call (SYN JS,) to the
:OPD syntax, which looks for — but does not insist upon — a
file number specifier (# < numeric expression > ). Then the
277
Appendix B
syntax joins with :SREAD, which looks for zero or more
variables.
Oops! Zero or more? Shouldn't that be one or more? That's
where the problem lies.
Do Not Use NOT
In all too many cases, the use of the NOT operator is
guaranteed to get you in trouble. If you don't believe it, try
this: PRINT NOT NOT 1.
The explanation of why the bug occurs is too lengthy to
give in detail here; suffice it to say that the precedence of NOT
is wrong. Remember the Operator Precedence Table we
displayed in Chapter 8 of Part 2? Look at what you got for the
go-onto-stack and come-off-stack precedence values for NOT.
Or look at location $ AC57, the NOT entry in OPRTAB .
NOT uses a 7 for both its precedence values. But wait a minute.
If two operators have the same apparent precedence (as in
NOT NOT A or even A + B + C), the expression executor will
pop the first one off the stack and execute it. But with a unary
operator, there is nothing to execute yet.
And the same bug exists for both unary minus and unary
plus, so - -3 and + +5 don't execute properly. Of course, since
unary plus doesn't really do anything, it doesn't matter. In the
case of unary minus, though, all but the last minus sign in a
string of minus signs is ignored (that is, - -3 produces -3 as a
result, instead of +3, as it should). But, by an incredible
coincidence, the damage that unary minus causes is invisible to
Execute Expression as a whole and only produces the error
noted.
The fix? Well, if we want to leave NOT where it is in the
order of things, the only way is to restructure the whole
precedence table. But if we are willing to accord it a very high
precedence, like unary plus and minus, we can fix it — and
plus and minus — by changing the bytes at $AC57, $AC64, and
$AC65 to $DC. And, thanks to the differing go-onto-stack and
come-off-stack values, we can stack as many NOTs, pluses, or
minuses as we want.
Are these all the bugs we know about that can be fixed
easily? No. But these are the easiest to understand or the
easiest to fix, and we thought they were instructive.
Of course, unless you have an EPROM board and burner
handy, you may not be able to take advantage of these fixes.
278
Appendix B
But at least now you may be able to work around them as you
program with good old buggy-version Atari BASIC.
And take heart. Remember Richard's Rule: Any nontrivial
piece of software has bugs in it. And the corollary: Any piece of
software which is bug-free is trivial.
279
Appendix C
Labels and
Hexadecimal
Addresses
AADD
AF52
CGTO
0017
CVFPI
AD56
EXEXPR
AAE0
AAPSTR
AB98
CI LET
0036
CVIFP
D9AA
EXOPOP
AB0B
n ADC
AF53
CIO
E456
DATAD
00B6
EXP
DDC0
ADFLAG
00B1
CIX
00F2
DATALN
00B7
EXP1
DE03
n AFP
D800
CLALL1
BD4F
n DCBORG
0300
EXP10
DDCC
AMUL1
AF5D
CLE
001D
DEGFLG
00FB
EXP2
DE20
AMUL2
AF46
CLEN
0042
DEGON
0006
EXP 3
DE26
APHM
000E
CLIST
0004
DIGRT
00F1
EXPAND
A881
ARGOPS
0080
CLPRN
002B
DIRFLG
00A6
EXPERR
DE4B
ARGP2
AC06
CLSALL
BD41
DNERR
BCB0
EXPINT
AB2E
ARGPOP
ABF2
CLSYS1
BCF1
DOSLOC
000A
EXPLOW
A87F
ARGPUS
ABBA
CLSYSD
BCF1
DSPFLG
02FE
EXPOUT
DE4A
ARGSTK
0080
CLT
0020
ECSIZE
00A4
EXPSGN
DE39
ARSLVL
00AA
CMINUS
0026
EEXP
00ED
EXSVOP
00AB
ARSTKX
00AA
CMUL
0024
ELADVC
BADD
EXSVPR
00AC
n ASCIN
D800
CNE
001E
ENDSTA
008E
FADD
DA66
ASLA
mac
CNFNP
0044
ENDVVT
0088
n FASC
D8E6
ATAN
BE77
CNOT
0028
ENTDTD
00B4
FBODY
000C
ATAN1
BE9A
COLD1
A008
EPCHAR
005D
FCHRFL
00F0
ATAN 2
BED4
COLDST
A000
ERBRTN
B920
FDB
mac
ATCOEF
DFAE
COLOR
00C8
ERGFDE
B922
FDIV
DB28
ATEMP
00AF
COMCNT
00B0
ERLTL
B924
FHALF
DF6C
ATNOUT
BEE2
CON
001E
ERNOFO
B926
FIXRST
B825
BININT
00D4
CONTLO
A8FB
ERNOLN
B928
FLD01
DD8F
BOTH
BDB3
CONTRA
A8FD
n ERON
B93E
n FLD0P
DD8D
BRKBYT
0011
COPEN
BBB6
EROVFL
B92A
FLD0R
DD89
BYELOC
E471
COR
0029
ERRAOS
B92C
FLD11
DD9E
n BYTE
mac
COS
BDB1
ERRDIM
B92E
n FLD1P
DD9C
C
0044
COX
0094
ERRDNO
B918
FLD1R
DD98
BYELOC
E471
CPC
009D
ERRINP
B930
FLIM
0000
n BYTE
mac
CPLUS
0025
ERRLN
B932
FLIST
BAD5
C
0044
CPND
001C
ERRNSF
B916
n FLOG10
DF01
CAASN
002D
CR
009B
ERRNUM
00B9
FLPTR
00FC
CACOM
003C
CREAD
0022
ERROOD
B934
FMOVE
DDB6
CADR
0043
CREGS
02C4
ERROR
B940
FMOVE1
DDB8
CALPRN
0038
CRPRN
002C
ERRPTL
B91A
FMOVER
A947
CAND
002A
CRTGI
BFF9
ERRSAV
00C3
FMPREC
0005
CASC
0040
CSASN
002E
ERRSSL
B936
FMUL
DADB
CCHR
003E
CSC
0015
ERRVSF
B938
n FNTAB
A829
CCOM
0012
CSEQ
0034
ERSVAL
B91C
FONE
DE8F
CCR
0016
CSGE
0031
ERVAL
B93A
FP9S
DFEA
CDATA
0001
CSGT
0033
ESIGN
00EF
FPI
D9D2
CDIV
0027
CSLE
002F
EVAADR
0002
FPONE
BE71
CDLPRN
0039
CSLPRN
0037
EVAD1
0004
FPORG
D800
n CDOL
0013
CSLT
0032
EVAD2
0006
FPREC
0006
n CDQ
0010
CSNE
0030
n EVARRA
0040
FPSCR
05E6
CDSLPR
003B
CSOE
0011
EVDIM
0001
FPSCR1
05EC
CEOS
0014
CSROP
001D
n EVNUM
0001
FPTR2
00FE
CEQ
0022
CSTEP
001A
EVSADR
0002
FR0
00D4
CERR
0037
CSTR
003D
EVSCAL
0000
FR0M
00D5
CEXP
0023
CTHEN
001B
EVSDIM
0006
FR1
00E0
CFFUN
003D
CTO
0019
EVSDTA
0002
FR1M
00E1
CFLPRN
003A
CUMINU
0036
EVSLEN
0004
FR2
00E6
CFOR
0008
CUPLUS
0035
EVSTR
0080
FRA10
DD01
CGE
001F
CUSR
00 3 F
n EVTYPE
0000
FRA1E
DD09
CGOSUB
000C
CVAFP
D800
n EWALU
0002
FRA20
DD05
CGS
0018
CVAL
0041
EXECNL
A95F
FRA2E
DD0F
CGT
0021
CVFASC
D8E6
EXECNS
A962
FRADD
AD3B
281
Appendix C
FRCMP
AD35
FRCMPP
AD32
FRDIV
AD4D
FRE
00DA
FRMUL
AD47
FRSIGN
00EE
FRSUB
AD41
FRUN
BAF7
FRX
00EC
FSCR
05E6
FSCR1
05EC
FSQR
BF08
FST01
DDAD
n FST0P
DDAB
FST0R
DDA7
FSTEP
0006
FSUB
DA60
FTWO
BF93
GDIOl
BC22
GDVCIO
BC1D
GET1
BC82
GET1IN
ABE9
GETINT
ABE0
GETLL
A9DD
n GETPI0
ABD8
GETPIN
ABD5
GETSTM
A9A2
GETTOK
AB3E
GETVAR
AB89
GFDISP
0003
GFHEAD
0004
n GFLNO
0001
GFTYPE
0000
GIOCMD
BD04
GIODVC
BC9F
GIOPRM
BD02
GLGO
BA92
GLINE
BA89
GLPCX
BAC4
GLPX
BAC6
n GNLINE
BA80
GNXTL
A9D0
GRFBAS
0270
GSTRAD
AB9B
GTINTO
ABE3
GWTAD
AC28
HIMEM
02E5
HMADR
02E5
n IBUFFX
00A9
ICAUX1
034A
ICAUX2
034B
ICAUX3
034C
ICAUX4
034D
ICAUX5
034E
ICBAH
0345
ICBAL
0344
ICBLH
0349
ICBLL
0348
ICCLOS
000C
ICCOM
0342
n ICDDC
000E
n ICDNO
0341
I C DRAW
0011
n ICFREE
00FF
a ICGBC
0006
n ICGBR
0004
ICGR
001C
ICGTC
0007
ICGTR
0005
n ICHID
0340
ICLEN
0010
n ICMAX
000E
n
ICOIN
0001
ICOIO
0003
n
ICOOUT
0002
n
ICPBC
000A
n
ICPBR
0008
ICPTC
000B
n
ICPTR
0009
ICPUT
0346
ICSBRK
0080
n
ICSDER
0083
n
ICSDNR
0081
n
ICSEOF
0003
n
ICSIVC
0084
n
ICSIVN
0086
n
ICSNED
0082
n
ICSNOP
0085
n
ICSOK
0001
ICSTA
0343
ICSTAT
000D
n
ICSTR
0002
n
ICSWPE
0087
IFP
D9AA
n
ILSHFT
DA 5 A
INBUFF
00F3
INDEX2
0097
INTLBF
DA51
101
BD0A
n
102
BD0E
103
BD10
104
BD12
105
BD19
n
106
BD1D
107
BD24
108
BD26
IOCB
0340
IOCBOR
0340
IOCMD
00C0
IODVC
00C1
I0TES2
BCB6
IOTEST
BCB3
ISVAR
BD2F
ISVAR1
BD2D
ii
LBPR1
057E
n
LBPR2
057F
LBUFF
0580
LDDVX
BCA6
LDIOST
BCFB
LDLINE
B578
LELNUM
00AD
LGCOEF
DF72
LISTDT
00B5
LLINE
B55C
LLNGTH
009F
LMADR
02E7
LOADFL
00CA
LOCAL
mac
LOG
DECD
n
L0G1
DEDB
LOG10
DED1
LOG10E
DE89
L0G2
DEEF
LOG 3
DEF3
L0G4
DEF9
LOG 5
DEDB
L0G6
DF46
LOG 7
DF53
LOGBTI]
DED3
LOGDOK
DF64
r
i LOGERF
. DED9
r
i LOGOUT
DF56
LOMEM
0080
LPRTOP
: B535
LSRA
mac
RNDDIV
B0A8
LSTMC
B63D
RNDLOC
D20A
MAXC I X
009F
ROLA
mac
MDEND
DB1A
ROM
A000
MDESUP
DCCF
RORA
mac
MDSUP
DCE0
RSHF0E
DC62
MEMFUL
B93C
RSHFT0
DC 3 A
MEMTOP
0090
RSHFT1
DC3E
n MEND1
DB1E
RSTPTR
B8AF
MEND2
DB21
RSTSEO
BD99
MEND3
DB24
RTNVAR
AC16
MEOLFL
0092
RUNINI
B8F8
MISCR1
0480
RUNSTK
008E
MISCRA
0500
SAVCUR
00BE
MV0TO1
DDB6
SAVDEX
00B3
MVFA
0099
SCANT
00AF
MVFR0E
DD34
SCOEF
BE41
MVFR12
DD28
SCRX
0055
MVLNG
00A2
SCRY
0054
MVTA
009B
SCVECT
BFF9
NATCF
000B
SEARCH
A462
NCTOFR
AB4D
SETDZ
BD72
NIBSH0
DBEB
SETLIN
B818
NIBSH2
DBE7
SETLN1
B81B
NLCOEF
000A
SETSEO
BD79
NOCD0
BD01
SGNFLG
00F0
NORM
DC00
SICKIO
BCB9
N0RM1
DC04
SIN
BDA7
NPCOEF
000A
SINDON
BE40
NSCF
0006
SINERR
BDA5
NSIGN
00EE
SINF1
BDF6
NXTSTD
00A7
SINF3
BE00
ONLOOP
00B3
SINF4
BE11
OPETAB
AA70
SINF5
BDE4
OPNTAB
A7E3
n SINF6
BDD5
OPRTAB
AC3F
SINF7
BDCC
OPSTKX
00A9
n SINOVF
BDCB
OUTBUF
0080
SIX
0480
P10COF
DE4D
SKBLAN
DBA1
n PATCH
BDA4
SKCTL
D20F
PATS I Z
0001
SKPBLA
DBA1
PI0V18
BE6B
SNTAB
A4AF
PI0V2
BE5F
SNX1
A050
PI0V4
DFF0
SNX2
A053
PLYARG
05E0
SNX3
A05D
PLYCNT
00EF
SOPEN
BBD1
PLYEV1
DD5B
SOX
0481
PLYEV2
DD6F
SPC
0482
PLYEVL
DD40
SQR
BEE5
PLYOUT
DD88
SQR1
BF00
POKADR
0095
SQR10
DF66
P0P1
AC0F
SQR2
BF84
POPRST
B841
SQR3
BF8A
PRCHAR
BA9F
SQRCNT
00EF
PRCR
BD6E
SQRDON
BF64
PRCX
BAA1
SQRERR
BEE3
PRDY1
BD59
SQRLP
BF2A
PREADY
BD57
SQROUT
BF92
PROMPT
00C2
SRCADR
0095
PSHRST
B683
SRCNXT
A490
PSTR
B480
SRCSKP
00AA
PTABW
00C9
SREG1
D208
PUTCHA
BA9F
SREG2
D200
QTEMP
00D9
SREG3
D201
RADFLG
00FB
SSTR
BA73
RADON
0000
STACK
0480
RESCUR
B6BE
STARP
008C
RISASN
AEA6
STENUM
00AF
RISC
AB64
STETAB
AA00
RML
0007
STINDE
00A8
RMSG
BD67
STKLVL
00A9
STMCUR
008A
282
Appendix C
STMLBD
00A7
STMSTR
00A8
STMTAB
0088
STOP
B7A7
STOPLN
00BA
STRCMP
AF81
SVCOLO
02FB
SVDISP
00B2
SVESA
0097
SVONTC
00B0
SVONTL
00B2
SVONTX
00B3
SWNTP
00AD
SWVTE
00B1
SYN
mac
SYNTAX
A060
TEMPA
00C4
TENDST
A9E2
n TESTRT
A9E7
TOPRST
0090
TRAPLN
00BC
TSCOX
00AB
TSLNUM
00A0
TSTALP
A3F7
TSTBRK
A9F4
TSTEND
B910
TSTNUM
DBAF
TVNUM
00D3
TVSCIX
00AC
TVTYPE
00D2
VNTD
0084
VNTP
0082
VNUM
00D3
VTYPE
00D2
WTP
0086
WARMFL
0008
WARMST
A04D
WWTPT
009D
XBYE
A9E8
XCLOAD
BBAC
XCLOSE
BC1B
XCLR
B766
XCMP
AD26
XCOLOR
BA29
XCOM
B1D9
XCONT
B7BE
XCSAVE
BBA4
XDATA
A9E7
XPCHR
B067
XDEG
B261
XPCOS
B125
XDIM
B1D9
XPDIV
AC9F
XDOS
A9EE
XPDLPR
AD82
XDPSLP
AD82
XPEQ
AC DC
XDRAWT
BA31
XPEXP
B14D
XEND
B78D
XPFLPR
AD7B
XENTER
BACB
XPFRE
AFEB
XERR
B91E
XPGE
ACD5
XFALSE
AD00
XPGT
ACCC
XFMFLG
00F1
XPIFP
AFD1
XFOR
B64B
XPIFP1
AFD5
XFORM
DE95
XPIFP2
AFD8
XGET
BC7F
XPINT
B0DD
XGOl
B6AE
XPL10
B143
XG02
B6A6
XPLE
ACB5
XGOSUB
B6A0
XPLEN
AFCA
XGOTO
B6A3
XPLOG
B139
XGR
BA50
XPLOT
BA76
XGS
B6C7
XPLPRN
AB1F
XGS1
B6CA
XPLT
ACC5
XIF
B778
XPMINU
AC8D
XINPUT
B316
XPMUL
AC96
XINT
B0E6
XPNE
ACBE
XITBT
B354
XPNOT
ACF9
XLET
AAE0
XPOINT
BC4D
XLIST
B483
XPOKE
B24C
XLOAD
BAFB
XPOP
B841
XLOAD1
BB04
XPOR
ACEE
XLOCAT
BC95
XPOS
BA16
XLPRIN
B464
XPPDL
B022
XNEW
A00C
XPPEEK
AFE1
XNEXT
B6CF
XPPLUS
AC84
XNOTE
BC36
XPPOWE
B165
XON
B7ED
XPPTRI
B02A
XOP1
BBED
XPRINT
B3B6
XOP2
BBFB
XPRND
B08B
XOPEN
BBEB
XPRPRN
AD7B
XPAASN
AD5F
n XPSEQ
AC DC
XPABS
B0AE
XPSGE
ACD5
XPACOM
AD79
XPSGN
AD19
XPADR
B01C
XPSGT
ACCC
XPALPR
AD86
XPSIN
BUB
XPAND
ACE3
XPSLE
ACB5
XPASC
B012
XPSLPR
AE26
XPATN
B12F
XPSLT
ACC5
XPSNE
ACBE
XPSQR
B157
XPSTIC
B026
XPSTR
B049
XPSTRI
B02E
XPUMIN
ACA8
XPUPLU
ACB4
XPUSH
AD16
XPUSR
B0BA
XPUT
BC72
XPVAL
B000
XRAD
B266
XREAD
B283
XREM
A9E7
XREST
B26B
XRTN
B719
XRUN
B74D
XSAASN
AEA3
XSAVE
BB5D
XSAVE1
BB62
XSETCO
B9B7
XSOUND
B9DD
XSTATU
BC28
XSTOP
B793
XTF
AD09
XT I
AD07
XTRAP
B7E1
XTRUE
AD05
XXIO
BBE5
ZF1
DA46
ZFP
00D2
ZFR0
DA44
ZICB
0020
ZPADEC
AFBC
ZPG1
0080
ZTEMP1
00F5
ZTEMP2
00C6
ZTEMP3
00F9
ZTEMP4
00F7
ZVAR
B8C0
ZXLY
DA48
283
Index
Symbols
in Operator Name Table 177
with string literals 130
(See also XPACOM)
in Operator Name Table 177
precedence of 69-70
with array, in ONT 180
with PRINT 98
$ in hexadecimal 115
in Operator Name Table 177
in variable names 15, 46
: (See alphabetic entry for terms
that begin with ":", like
:LPRSCAN) 58
in Operator Name Table 177
with PRINT 98
; in Operator Name Table 177
with PRINT 98
# in Operator Name Table 178
with PRINT 98
< = (See also XPLE, XPSLE) 178-79
< > (See a/so XPNE, XPSNE) 178-79
> = (See also XPGE, XPSGE) 178-79
< (See a/so XPLT, XPSLT)
in ABML 34-39
in Operator Name Table
178-79
precedence of 56
> (See also XPGT, XPSGT)
in ABML 34-39
in Operator Name Table
178-79
precedence of 56
(See also XPEQ, XPSEQ) 41-42,
58-64
in Operator Name Table
178-79
precedence of 55-56
A in Operator Name Table 178
precedence of 55-56, 58-64
(See also XPMUL, FMUL,
FRMUL)
in Operator Name Table 178
precedence of 55-56, 58-64
+ (See also XPPLUS, XPUPLUS,
FADD, FRADD)
in Operator Name Table 178
unary 179, Appendix B
precedence of 55-56, 58-64
(See also XPMINUS, XPUMINUS,
FSUB, FRSUB)
in Operator Name Table 178
unary 179, Appendix B
I (See also XPDIV, FDIV, FRDIV)
178
( (See also XPDLPRN, XPALPRN,
XPSLPRN)
in variable names 15, 46
mathematical, in Operator
Name Table 179
precedence of 69-70
string, array, DIM, and func-
tion, in ONT 179-80
tokens for 70
) (Seen/soXPRPRN)
in Operator Name Table 179
precedence of 69-70
: = 34-37
! 34, 37, 41
= < 56
! as EOE operator 34-35, 58-64
? 95
Numbers
6502 microprocessor 1-2, 40
AADD 202, $AF52
AADR 66-68
AAPSTR 191, $AB98
ABS (See also XPABS) 69, 180, 206
Absolute Non-Terminal Vector (See
ANTV)
ABML (Atari BASIC Meta-Language)
33-34, 37
AD Appendix A
addition (See FADD, FRADD)
ADR 180
AMUL202, $AF5D
AMUL 2 202, $AF46
AND (See also XPAND) 89, 179
ANTV (in ABML) 40-42, 44, 162
APHM 13, 143, $000E
application high memory 13
ARGOPS 23, 66, 143, $0080
ARGP2 192, $AC06
ARGPOP 192, $ABF2
285
Index
ARGPUSH 65, 191, $ABBA
ARGSTK 23, 66, 143, $0080
arguments 56
Argument Stack 12, 23, 56-67
entry format 66-68
example of use 56-64
arithmetic assignment operator (Sec
XPAASN)
arithmetic expressions 12, 55-65
array variables 15-16, 18, 66-67, 69-70,
106-7, 127
Array/String Table (See String/ Array
Table)
ARSLVL 66, 144, $00AA
ARSTKX 144, $00AA
ASC (See also XPASC) 180, 204
ASCIN 246, $D800
ASLA: Appendix A
assembler 2
assembly language 2-3
ATAN[X] 244, $BE77
Atari BASIC
as a high-level language 2-5
location in memory 14
Meta-Language (ABML) 33
ROM pointer 143, $A000
Atari cartridge vectors 272
ATASCII 9, 47, 88, 90, 116, 135-36
AT LINE (in error message) 74, 231-32,
$B9AE
ATN (See a/so XPATN, ATAN) 180, 207,
244
AUXii (i.e., AUX1, AUX2, etc.) 99-100
B
BASIC ROM pointer 143, $A000
binary 115, 119-20
blanks in program lines 27, 29
block move routines 20-23
BNF33
BREAK 50, 96, 101
BRKBYT 101, 110, 143, $0011
buffer (See also INBUFF, OUTBUFF,
LBUFF) 13, 65, 145
bugs Preface , 20-21, Appendix B
BYE (See also XBYE, :SBYE) 105
BYELOC 143, $E471
byte 119-20
BYTE: Appendix A
CALPRN 70
carriage return character 177
cartridge vectors 272
CDLPRN 70
CDSLPR 70
CFLPRN 70
Change Last Token (in ABML) 41-42
CHNG (in ABML) 41-42, 45, 162
CHR$ (See also XPCHR) 180, 205
CIO 25, 85, 91, 93, 102, 143, SE456
CIX 26, 29-30, 43, 45, 47
CLOAD(Seea/soXCLOAD, :SCLOAD)
84, 237
CLOG 180
CLOSE (See k/soXCLOSE, :SCLOSE)
W0, 146, 239
CLPRN 70
CLR (See also XCLR, :SCLR) 83, 103, 224
CLSALL 242, $BD41
CLSYS1 99, 241, $BCF1
CLSYSD 241, $BCF1
COLDSTART86, 101, 109-UO, 147,
$A000
COLOR (See also XCOLOR, :SCOLOR)
execution 91, 233
memory location 91-92, 144,
$00C8
color registers (See also CREGS) 91-92,
143
COMMON (unused command; see
XCOM, :SCOM)
compiler 3-4
constants 33-34, 130
CONT (See also XCONT, : SCO NT)
71-72, 225
:CONT2 183, Appendix B, $A954
:CONT3 183, Appendix B, $A950
:CONT4 183, Appendix B, $A95B
CONTLOW 20-23, 31, 77, 182, $A8FB
CONTRACT 20-22, 28, 182-83, $A8FD,
Appendix B
conversion
ASCII to floating point 145,
$00ED-$00F1
decimal to hexadecimal 116-17
floating point to ASCII (See also
CVFASC) 250-52
floating point to integer (See also
CVFPI, FPI) 197, 253-55
hexadecimal to decimal 116
integer to floating point (See also
CVIFP) 252-53
COPEN 237, $BBB6
COS (See also XPCOS, COS[X]) 105, 180,
207, 243
COS[X] 243, SBDB1
COX 26, 27-30, 43, 45, 48, 97-98, 144,
$0094
CPC 43-44, 144, 153, $009D
286
Index
CPU stack 43, 51, 74-75, 109-110
CREGS 143, S02C4
CRTGI 143, $BFF9
CSAVE(Seert/soXCSAVE, :SCSAVE)
84, 237
CSLPRN 70
Current Program Counter (See CPC)
CVAFP 96, 246, $D800
CVFASC 98, 250, $$D8E6
CVFPI (See also FPI) 197, $AD56
CVIFP 252, $D9AA
:CVFR0 263, $DC70
D
Dl 169, $A705
DATA (See also XDATA, :SDATA)
103-104, 110,131,140
DATAD 103-4, 110, 144, $00B6
DATALN 103-4, 110, 144, $00B7
DCBORG 143, $0300
debugger 2
decimal 115-17
:DECINB 265, $DCC1
definition
in language creation 33-34
DEG (See also XDEG, :SDEG) 105, 145,
211
DEGFLG 145, $00FB
deleting lines 28
DEND 81-82
DIM (See also XDIM, SUM) 16-17, 66,
127
and "(" operator 70, 197
effects on tables 16-17
execution 106-7, 210
DIMENSION TOO SMALL error (See
also ERRDIM) 96
direct statement 32, 49, 51-52, 74
DIRFLG 26, 30-32, 144, $00A6
Disk Device Dependent Note
Command 100
division (SeeFDIV, FRDIV, '/')
DOS (See also XDOS, :SDOS) 105, 109
DOSLOC 143, $000A
DPEEK 122
DPOKE 122
DRAWTO (See also XDRAWTO,
:SDRAWTO) 92-93, 146, 233
deus ex machina 40-41, 46
DSPFLG 143, $02FE
DST 81-82
DWT 81-82
ECHNG 45, 154, $A2BA
Editor (See Program Editor)
:EGTOKEN (See GETTOK)
ELADVC 83, 235, $BADD
END (Secn/soXEND, :SEND) 72-72, 225
End Of Expression (See EOE operator)
end-of-statement token (See also EOS) 76
ENDSTAR 139, 143, $008E
ENDWT 143, $0088
English 37
ENTDTD 85-86, 110, $00B4
ENTER (See also XEbiTER, :SENTER) 23,
25, 123, 128, 140
device 71, 85-86
execution 85-86, 235
EOE operator 57-66
EOL character 58, 95-96, 98, 99-100, 143,
177
EOPUSH 65, 189, $AB15
EOS 169, $A6F8
EOS2 173, $A773
EPCHAR 143
equates
ICCOM value 146
ICSTA value 146
miscellaneous 143
Run Stack 147
variables 147
ERBRTN 230, $B920
ERGFDE 230, $B922
ERGFDEL 77, 79, 224, $B74A
ERLTL 230, $B924
ERNOFOR 78, 230, $B926
ERNOLN 75, 230, $B928
ERNTV 44, 152, $A201
ERON 230, $B93E
EROVFL 230, $B92A
ERRAOS 230, $B92C
ERRDIM 106, 230, $B92E
ERRDNO 230, $B918
ERRINP 96, 230, $B930
ERRLN 230, $B932
:ERRM1 231, $B961
:ERRM2 71, 231, $B974
ERRNSF 83, 230, $B916
ERRNUM 72, 101, 110, 144, $00B9
ERROOD 104, 230, $B934
ERROR 71, 88, 101, 106, 231, $B940
error handling 73-74
and DATA-READ 104
and DIM 106
and GOTO 75
and INPUT 96
and LOAD 83
287
Index
and SETCOLOR 91
and SOUND 93
and TRAP 73, 231
execution 231
in I/O 101, 109, 146
in line processing 25-26, 28
in LISTing 88
in statement processing 29-30
in syntactical analysis 38-39
messages 230
missing FOR entry 78
missing GOSUB entry 79
missing line number 77
that stops program 73-74
ERRPTL 83, 230, $B91A
ERRSAV 144, $00C3
ERSVAL 230, SB91C
ERVAL 91, 93, 230, $B93A
ESRT (in ABML) 40-41, 44, 47, 162
:EVEN 249, $D8CE
EXECNL 32, 49, 75, 183, SA95F
EXECNS 183, $A962
Execute Expression (See also EXEXPR)
12, 55-70, 105, 189-90
Execution Control 49-54, 75, 77, 83,
183-85
EXECUTION OF GARBAGE error (See
also XERR) 106
executor (See Program Executor)
EXEOL 184, $A989
EXEXPR 64-65, 189, $AAE0
EXNXT 65, 189, $AAE3
EXOP 65, 69, 190, $AB20
EXOPOP 65, 189, $AB0B
EXOT 65, 189, $AAEE
EXP (See also XPEXP) 180, 208
:EXP 162, $A60D
EXP[X] 268, $DDC0
EXP10[X] 268, $DDCC
EXPAND 20-23, 106-7, 144, 181, SA881,
Appendix B
EXPINT 65, 190, $AB2E
EXPL 173, $A76C
EXPL1 173, $A76F
EXPLOW 20-22, 31, 77-78, 181, SA875
exponential operator (i.e., A**B; see
XPPOWER)
expressions (See also Execute
Expression)
in ABML 34
rearrangement of 55-65
Expression Non-Terminal Vector (See
VEXP)
Expression Rearrangement Procedure
(See also expressions, rearrangement
of) 57
EXPTST 65, 189, $AAFA
EXSVOP65, 144, $00AB
EXSVPR 144, $00AC
External Subroutine Call (See ESRT)
FADD 255, $DA66
FAIL 44-45, 153, $A26C
false (See XFALSE, :FALSE)
: FALSE 224, $B788
FDB: Appendix A
FDIV 259, $DB28
files
LIST-ENTER format (See FLIST)
SAVE-LOAD format 81-82
FIXRSTK 226-27, $B825
FLIST 235, $BAD5
floating point 126-27
add (See FADD, FRADD)
ASCII to fp conversion 145,
$00ED-$00F1
fp to ASCII conversion 250-52,
$D8E6-$D9A9
fp to integer conversion 253-55,
$D9D2-$DA5F
comparisons 196-97
divide (See FDIV, FRDIV)
in ROM 14, 143, 246-72,
$D800-$DFF6
integer to fp conversion 252-53,
$D9AA-$D9CF
load/store 267
multiply (See FMUL, FRMUL)
routines 255-67
subtract (See FSUB, FRSUB)
zero page work area 143, 145,
$00D2-$00EC
FLOG10 270, SDF01
FMOVER 183, Appendix B, $A947
FMUL 257 SDADB
:FNZER0 264, $DCA4
FOR(Seefl/soXFOR, :SFOR) 12
entry on Runtime Stack 18-19,
76-77, 133-34
execution 77-78, 220-21
tricks with 131
FPI 253, $D9D2
FPORG 143, 246, $D800
FRO 145, $00D4
FROM 145, $00D5
FR1 145, $0OEO
FR1M 145, $00E1
FR2 145, $0OE6
FRAim (i.e., FRA10, FRA20) 266, $DD01
FRADD 196, $AD3B
288
Index
FRCMP 196, $AD35
FRDIV 196, $AD4D
FRE
floating point memory location
145, $00DA
function (See also XPFRE) 180, 204
FRMUL 196, $AD47
FRSUB 196, $AD41
FRUN 236, $BAF7
FS 172, $A751
FSTEP 168, $A6DE
FSUB 255, $DA60
Function Name Table 180
functions (See entry under individual
function name)
G
GDI01 101, 239, $BC22
GDVCIO 100-101, 239, $BC1D
GET (See also XGET, :SGET) 97, 146,
239, Appendix B
GET1 239, Appendix B, $BC82
GET1INT 192, $ABE9
GETADR 44, 152, $A215
:GETCHAR260, $DB94
:GETDIG 265, $DCB9
GETINT 99, 192, $ABE0
GETLL 31, 53, 185, $A9DD
GETLNUM 151, $A19F
GETPINT 192, $ABD5
GETSTMT 31, 52-53, 54, 75, 87, 103-4,
184, $A9A2
GETTOK 128, 190, $AB3E
:GETTOK 77, 79, 223, SB737
GETVAR 191, $AB89
GIOCMD 99, 241, $BD04
GIODVC 99, 240, $BC9F
GIOPRM 241, $BD02
GLINE 234, $BA89
GNLINE 234, $BA80
GNXTL 31, 51, 53, 185, $A9D0
GOSUB (See also XGOSUB, :SGOSUB)
12, 43, 79-80, 103, 127
entry on Runtime Stack 18-19,
133-34
execution 79, 221-22
in ABML 40, 42
in Operator Name Table 178
GOTO (See also XGOTO, :SGOTO) 75,
123, 128, 177, 221-22
GRAPHICS (See also XGR, :SGR) 86, 91,
234
grammar 33-35, 37
:GRF 205, $B030
GRFBAS 143, $0270
GSTRAD 191, $AB9B
GWTADR 193, $AC28
H
hexadecimal 2, 115-17
high level languages 3
high memory address 13
HIMEM 143, $02E5
HMADR 13, 143, $02E5
I
ICCOM 146, $0342
ICSTA 146, $0343
IF (See also XIF, :SIF) 76, 154, 224
IFA 174, $A799
INBUFF 23, 25, 47, 88, 91, 98
INPUT (See h/soXINPUT, :SINPUT)
95-96, 143, 145, 213-14, Appendix B
INT (See also XPINT) 180, 206
interpreter 1, 3-5
INVAR 46
I/O 91-93, 95-102, 109, 234-43
I/O Call Routine 101-2, 241, $BD0A
IOCB n (i.e., IOCB 0, IOCB 1, etc.)
85-87, 91-92, 95, 99-101, 105, 110
close all (See CLSALL)
control block 146, $0340-$0350
ICCOM value equates 146
ICSTA value equates 146
IOCBORG 143, $0340
IOCMD 99, 102, 144, $00C0
IODVC 144, $00C1
\On (i.e., IOl, 102, etc.) 83, 100, 202-2
IOTEST86, 91, 93, 100, 202, 240, $BCB3
ISVAR 46, 241, $BD2F
ISVAR1 100, 241, $BD2D
joysticks (See STICK, :STRIG)
JS Appendix A
labels 34
language
creation of 33-39
problems with 1-2
high level 3
LBUFF 23, 25, 30, 145, $0580
LDDVX 240, $BCA6
LDIOSTA 241, $BCFB
LELNUM 87, 144, $00AD
LEN (See also XPLEN) 180, 203
289
Index
LET (See also Execute Expression, XLET,
:SLET)8, 11,29,42, 105
LIFO (last-in, first-out) stack 12, 43, 133
Line Buffer 23, 25-26
line number 27-28, 49-50, 52
line processing 25-28, 31-32, 95-96
LINE TOO LONG error (See also ERLTL)
25-26, 43, 48
LIST (See also XLIST, :SLIST) 15, 25,
123, 1 28, 129, 139-40
device 71, 242
entry in Runtime Stack 19
execution 86-87, 216-17, 222
subroutines 88-90
LISTDTD 86-87, 110, 144, $00B5
:LLINE 87, 88, 218-19, $B55C
LLNGTH 50, 54, 72, 144, $009F
LMADR 13, 143, $02E7
LOAD (See also XLO AD, :SLOAD)
81-86, 109, 123, 139-40
as block (See LSBLK)
execution 83-84, 236
file format 81-82
LOADFLG 109-110, 144, S00CA
LOCAL: Appendix A
LOCATE (See also XLOCATE,
:SLOCATE) 92, 240, Appendix B
LOG (See also XPLOG) 180, 208, 270,
$DECD
LOG10 (See also XPL10) 208
LOG10[X] 270, $DED1
LOMEM 23, 115
LI 176, $A7C0
low memory address 13
LPRINT (See a/so XLPR1NT, :SLPRINT)
98-99, 216
:LPRTOKEN 71, 88-89, 90, 218, $B535
:LPTWB218, $B54F
LSBLK 237, SBB88
:LSCAN 89-90, 217-18, SB50C
LSRA: Appendix A
:LSTMT 88-89, 219-20, $B590
L2 176, $A7C4
M
machine language 1-2
macros Appendix A
mantissa 127
MAXCIX 26, 29, 144, $009F
MDESUP 265, $DCE0
MEMFULL 230, $B93C
memo pad 105
memory
management routines 20-23
organization 13-14
pointer addresses 13, 83
MEMTOP 20-21, 143, $0090
MEOLFLG 143, $0092
meta-language 33
MOD (See modulo)
modulo 120-22
multiplication (SeeFMUL, FRMUL, '*')
multipurpose buffer 13, 65, 82, 110
:MV6RS228, $B88F
MVFR0E 267, $DD34
MVFR12 266, $DD28
MVLNG 183, Appendix B
N
NEXT (See also SNEXT) 18, 131
execution 78-79, 222-23
in Pre-compiler 43-45, 151, $A1E2
NEW (See a/so XNEW, :SNEW) 109-110,
123, 128
NFP 164, $A672
NFSP 176, $A7CE
NFUN 164, A65F
NFUSR 164, $A669
NIBSH0 261, $DBEB
NMAT 164, $A651
NMAT2 164, $A659
non-terminal 35, 40
NOP 163, $A62E
NORM 262, $DC00
NOT (See also XPNOT) 178, Appendix B
NOTE (See also XNOTE, :SNOTE) 100,
239
NSMAT 173, $A777
NSML 174, $A78C
NSML2 174, $A790
NSVAR 169, $A708
NSVRL 169, $A710
NSV2 170, $A714
NULL (in ABML) 162
numeric constants 89, 131
numeric variable 7-8, 95
NV 162, $A622
NVAR 163, $A64C
NXSC 44, 153, $A2A1
NXTSTD 50, 54, 72, 144, $00A7
o
ON (See also XON, :SON, ONI) 80, 226
ONI 173, SA768
OPD 171, $A72C
OPEN (See also XOPEN, :SOPEN,
COPEN, SOPEN) 99-100, 123, 146,
238
Operating System (OS) 13-14, 92-93,
105, 109
~
290
Index
Operator Execution Table (See also
OPETAB) 9, 187-89
Operator Name Table (See also
OPNTAB) 9, 46, 89, 135-36, 177-80
Operator Precedence Table (See also
OPRTAB) 9-10, 56, 137-38, 193-94,
Appendix B
Operator Stack 12, 23, 56-67
entry format 66
example of use 56-64
Operator Token (in ABML) 42, 131
operators 33-34
array 69
EOE 57-66
BASIC functions as 69
execution of 69-70
precedence of 56-64, 69
SOE 57-66
token 89
OPETAB (See also Operator Execution
Table) 187, $AA70
OPNTAB (See also Operator Name
Table) 135-36, 177, $A7E3
OPRTAB (See also Operator Precedence
Table) 137-38, 193, $AC3F
OPSTKX 66, 144, $00A9
OR (See also XPOR)
in ABML 41, 44-45, 162
in Operator Name Table 179
OUTBUFF 23, 26-28, 30-31, 45, 143,
$0080
PADDLE (See also XPPDL) 180, 204
Pascal 3
pass/fail 37-40
PEEK(Seea/soXPPEEK)69, 115, 219-22,
137-38, 180, 203
PEL 175, $A7A9
PELA 175, $A7B2
PES 175, $A7AC
PILOT 3
PL6RS 229, $B89E
PLOT (See also XPLOT, :SPLOT) 92, 234
PLYEVL 267, $DD40
POINT (See also XPOINT, :SPOINT)
100-101, 239
pointers
line processing 25-27
memory 13
multipurpose buffer 65
tables 20, 83, 110, 143
POKADR 144, $0095
POKE (See also XPOKE, : SPOKE) 105
execution 105, 211
how to use 119-22
polynomial evaluation (See also
PLYEVL) 267
POP (See a/so XPOP, :SPOP) 18, 227
BASIC command 80
in Pre-compiler 44, 152, $A252
POP1 192, $AC0F
POPRSTK 77, 78-80, 227, $B841
POSITION (See also XPOS, :SPOS) 92,
233
power of (See also XPPOWER) 208-9
PR1 175, $A7A0
PR2 175, $A7A6
PRCHAR 89, 235, $BA9F
PRCR 242, $BD6E
PRCX 92, 99, 235, $BAA1
PREADY 242, $BD57
precedence (See operators, Operator
Precedence Table)
Pre-compiler 10-11, 25-26, 33-48
pre-compiling interpreter 5
PRINT (See a/soXPRINT, : SPRINT)
97-98, 110, 123, 127, 214-16
Program Editor 11, 25-32, 110,
Appendix B
Program Executor 8, 11-12, 32
PROMPT 144, $00C2
prompt 95
PS 176, $A7BC
PSHRSTK 77, 78-79, 221, $B683
PSL 175, $A7B6
PSLA 175, $A7B9
PSn (i.e., PS1, PS2, etc.) 57, 59-65
PTABW 97, 144, $O0C9
PTRIG (See also XPPTRIG) 180, 204
PUSH 43, 152, $A228
PUSR 177, $A7DA
PUSR1 177, $A7DD
PUT (See also XPUT, :SPUT) 92, 99, 146,
239
PUTCHAR 235, $BA9F
R
RAD (See also XRAD, :SRAD) 105, 211
RADFLG 105, 110, 145, $00FB
RAM tables 10, 81-82
:RCONT228, $B872
READ (See a/so XREAD, :SREAD) 95-96
bugs Appendix B
entry in Runtime Stack 19
execution 103-4, 211-13, 222
READY (See also PREADY) 51-52, 110,
242
rearrangement (See expressions,
rearrangement of)
Relative Non-Terminal Vectors (in
ABML) 42
291
Index
REM (See also XREM, :SREM) 106, 131,
140, 154
RESTORE {See also XRESTORE,
:SRESTORE) 103-4, 211
RETURN (See also XRTN, :SRET) 12, 18,
79-80, 223-24
Return (in ABML) 41
:REXPAN228, $B878
Richard's Rule Appendix B
RISASN 96
RND (See also XPRND) 37, 69, 180, 206
RNDLOC 143, $D20A
RNTV 44
ROLA: Appendix A
ROM 143, $A000
ROM tables 9-10, 135-36
RORA: Appendix A
RSHF0E 263, $DC62
RSHFT0 263, $DC3A
RSHFT1 263, $DC3E
RSTPTR229, $B8AF
RSTSEOL 100, 242, $BD99
RTN (in ABML) 41, 44-45, 162
RTNVAR 96, 193, $AC16
RTS 45, 51, 96, 106
RUN (See also XRUN, :SRUN,
RUNINIT)
as direct statement 49, 52
execution 71-73, 224
initialization 103, 105
with implied LOAD (See also
FRUN) 235
RUNINIT 230, $B8F8
RUNSTK 19, 143, $008E
Runtime Stack 10, 14
and FOR, NEXT, GOSUB,
RETURN 76-80
entry format 18-19
listing 133-34
pointer to 19
SADR 66-68
SAP (Simple Arithmetic Process) 33-39
SAVCUR 144, $00BE
:SAVDEX228, $B88A
SAVE (See also XSAVE, :SSAVE) 81-83,
85-86, 139
as block (See LSBLK)
execution 82-83, 237
file format 81-82
SAVE "C:" 84
SAVEOP 57, 59-64
:SAVRTOP228, SB881
:SBYE167, $A6BE
scalar 126
SCANT 89-90, 97-98, 144, $00AF
SCLOAD 167, $A6BE
SCLOSE 170, SA721
SCLR 167, $A6BE
SCOLOR 167, $A6BD
SCOM 173, SA760
SCONT 167, $A6BE
SCRADR 90
screen editor 25
SCRX 92, 143, $0055
SCRY 92, 143, $0054
:SCSAVE167, $A6BE
SCVECT 272, $BFF9
SDATA 176, $A7CB
SDEG 167, $A6BE
SDIM 173, $A760
SDOS 167, $A6BE
SDRAWTO 172, $A75D
SEARCH 29, 47, 135, 158, $A462
SEND 167, $A6BE
SENTER 170, $A724
SETCODE 27-29, 154, $A2C8
SETCOLOR (See also XSETCOLOR,
:SSETCOLOR) 91-92, 232
SETDZ 242, $BD72
SETLINE 54, 226, $B818
SETLN1 50, 54, 226, $B81B
SETSEOL99, 242, $BD79
SFNP 177, $A7D6
:SFOR167, $A6D2
SFP 165, $A678
SFUN 165, SA68A
:SGET 168, $A6E8
SGN (See also XPSGN) 180
SGOSUB 167, $A6BD
SGOTO 167, $A6BD
SGR 167, $A6BD
SICKIO 101, 240, $BCB9
:SIF174, $A794
SIN (See also XPSIN, SIN[X]) 105, 180,
207, 243
SIN[X] 243, $BDA7
:SINPUT 169, Appendix B, $A6F4
SKBLANK 29, 261, $DBA1
SKCTL 143, $D20F
SKPBLANK 260-61, $DBA1
:SLET167, $A6C0
SLIS 171, $A73C
SLIST 171, $A733
SLOAD 170, $A724
SLOCATE 168, $A6E2
SLPRINT 169, $A700
SMAT 165, $A694
SMAT2 166, $A69C
:SNEW167, $A6BE
292
Index
:SNEXT168, $A6EA
:SNOTE172, $A74A
SNTAB (See also Statement Name Table)
115, 135-36, 159, $A4AF
SNX2 86, 101, 148, $A053
SOE operator 57-66
: SON 173, $A763
SOP 166, $A6A2
SOPEN 238, $BBD1
:SOPEN170, $A71A
SOUND (See a/so XSOUND, :SSOUND)
93, 232
sound registers (See also SREGu,
:SKCTL)93, 143
:SPLOT172, $A75D
:SPOINT172, $A74A
: SPOKE 172, $A75D
:SPOP167, $A6BE
:SPOS172, $A75D
: SPRINT 169, $A6FC
:SPUT 166, $A6BA
speed comparisons 3-5
SQR (See also XPSQR, SQR[X] 180, 208,
245
SQR[X] 245, $BEE3
:SRAD167, $A6BE
SRCADR 29, 43, 48, 144, $0095
SRCONT 45-46, 154, $A2E6
:SREAD 169, Appendix B, $A6F5
SREGn (i.e., SREG1, SREG2, etc.) 143,
$D208, SD201-2
SREM 176, $A7C8
SREST 168, $A6EF
SRET 167, $A6BE
SRUN 170, $A727
SSAVE 170, $A724
SSETCOLOR 172, $A75B
SSOUND 172, $A759
SSTATUS 171, $A741
SSTOP 167, $A6BE
ST (See Statement Table)
stack (See also Argument Stack,
Operator Stack, Runtime Stack,
CPU stack) 2, 12
STACK OVERFLOW error (See also
ERRAOS) 66
STARP 18, 139, 143, $008C
Start Of Expression (See SOE Operator)
STAT 171, $A744
statement
execution 50-51
processing 28-31
Statement Execution Table (See also
STETAB) 9, 185-87
Statement Name Table (See also SNTAB)
9, 40, 135-36, 159-61
Statement Name Token 8, 12, 106
Statement Syntax Table 10-11, 33, 40
Statement Table 10-11, 14, 49-50, 52
entry format 17, 131
in LIST 87-88
in NEW 110
in SAVE and LOAD 81-82
listing in token form 129-31
processing 31
STATUS (Sees/soXSTATUS, :SSTATUS)
W0, 146, 239
:STCHAR264, $DC9F
STCOMP 165, $A67E
STENUM 29, 48, 144, $00AF
STEP
execution 77-78
in Operator Name Table 178
in Runtime Stack 19
STETAB (See also Statement Execution
Table) 185, $AA00
STICK (See also XPSTICK) 180, 204
STINDEX 65, 87-88, 144, $00A8
STKLVL 43, 144, $00A9
STMLBD 29-30, 144, $00A7
STMTAB 17, 131, 143, $0088
STMCUR 20, 31-32, 49-54, 64, 72, 88,
143, $008A
STMSTRT 30, 144, $00A8
:STNUM264, $DC9D
STOP (See also XSTOP, : SSTOP) 50,
72-72, 124, 225
STOPLN 71-72, 110, $00BA
STR (See a/so XPSTR)
function 205
routine 165, $A682
STR$ 180
: STRAP 167, $A6BD
STRCMP 202, $AF81
STRIG (See also XPSTRIG) 180, 204
String/ Array Table 10, 106-7, 127
pointers into 15-16, 143
entry format 18
SAVEing 139
use of, in Execute Expression
66-67
string
assign operator 200-202
bug Appendix B
comparisons (See STRCMP)
constants (literals) 89, 131
variables 15-18, 66-67, 70, 96, 107
subscripts (See arrays, '(' and ',')
subtraction (See FSUB, FRSUB, '-')
SVAR 165, $A68F
SVCOLOR 92, 143, $02FB
SVDISP 77, 79, 144, $00B2
293
Index
SWNTP 26, 144, $OOAD
SVWTE 27, 144, $C0B1
:SXIO170, $A718
symbols 1, 4
in language creation 33-39
SYN: Appendix A
SYNENT42, 151, $A1C3
SYNTAX 74, 148, $A060
syntax 1, 10-11, 23, 29-30
analysis of 37-39
bugs with Appendix B
creation of 35-39
instruction codes 40-42
memory organization 148-53
tables 40-42, 162-77
syntaxer (See Pre-compiler)
Syntax Stack 23, 43
tables 9-70
Function Name Table 180
Operator Execution Table 9,
187-89
Operator Name Table 9, 46, 89,
135-36, 177-80
Operator Precedence Table 9-10,
56, 137-38, 193-94, Appendix B
RAM tables 11, 81-82, 110, 143
ROM tables 9-10
Runtime Stack 10, 14, 18-19,
76-80, 133-34
Statement Execution Table 9,
185-87
Statement Name Table 9, 40,
135-36, 159-61
Statement Syntax Table 10-11
Statement Table 10, 14, 17, 31,
49-50, 52, 81-82, 110, 129-31
String/Array Table 10, 13, 18,
106-7, 127
syntax tables 40-42, 162-77
Variable Name Table 10, 13, 15,
26, 46, 81-82, 110, 123, 135-36
Variable Value Table 10, 13, 15-16,
27, 46, 66-67, 78, 81-82, 106-7,
125-28
TENDST51, 52, 185, $A9E2
terminal symbol 34-36
TERMTST 44-45, 154, $A2A9
TEXP 172, $A755
THEN (See also XIF, :SIF) 58, 76, 178
TNCON 47, 157, $A400
TNVAR 46, 155, $A32A
TO 131, 178
tokens 5-8, 15, 17, 88-89, 135
TOPRSTK 143, $0090
transcendental functions 207-9
translators 1-3
TRAP (See alsoXTRAP, : STRAP) 73, 76,
225, 231
TRAPLN 73, 76, 110, 144, $00BC
true (See XTRUE)
TSCON 47, 157-58, $A428
TSLNUM 27, 52-53, 77, 79, 87, 144,
$O0AO
TSTALPH 157, $A3F3
:TSTCHAR261, $DBBB
TSTEND 230, $B910
TSTNUM 261, $DBAF
TSVAR 155, $A32E
TVAR 155, $A330
U
UNARY 162, $A618
unary + and - 179, Appendix B
USR (See also XPUSR) 180, 206
VAL (See also XPVAL) 180, 204
Variable Name Table 10, 13, 26, 46
entry format 15
in NEW 110
in SAVE and LOAD 81-82
listing 123-24, 135-36
variables (See also numeric v, string
v, array v) 8, 95
finding and listing 139-40
listing 123-28
tokens 8, 88-89
Variable Value Table 10, 13, 27, 46,
66-67, 78, 106-7
entry format 15-17
in SAVE and LOAD 81-82
listing 125-28
VEXP (in ABML) 41, 44-45, 162
VNT (See Variable Name Table)
VNTD 20, 123, 143, $0084
VNTP 15, 123, 139, 143, $0082
VNUM 66-68
VVT (See Variable Value Table)
VVTP 17, 143, $0086
w
WARMFLG 109-110, 143, $0008
WARMSTART 109-110, 148, $A04D
WORD 122
WVVTPT 144, $009D
294
index
XBYE 205, 185, $A9E8
XCLOAD 237, $BBAC
XCLOSE 200, 239, $BC1B
XCLR 72, 224, $B766
XCMP 196, $AD26
XCOLOR 92, 233, $BA29
XCOM 210, $B1D9
XCONT 72-72, 225, $B7BE
XCSAVE 237, $BBA4
XDATA 203, 185, $A9E7
XDEG 205, 211, $B261
XDIM 206-7, 210, $B1D9
XDOS 205, 185, $A9EE
XDRAWTO 91, 92-93, 233, SBA31
XEND 52, 72-72, 225, $B78D
XENTER 85-86, 235, $BACB
XEOS 167, $A6BD
XERR 206, 230, $B91E
XFALSE 195, $AD00
XFOR 51, 77-78, 220, SB64B
XFORM 269, $DE95
XGET 97, 239, $BC7F
XGOSUB 79, 87, 103, 221, SB6A0
XGOTO 75, 76, 79-80, 221, $B6A3
XGR 92, 234, $BA50
XGS 222, $B6C7
XIF 76, 224, $B778
XIN0 96, 213, $B326
XINA 95-96, 104, 213, $B335
x index 69-70
XINPUT 95-96, 104, 213, $B316
XINT 207, $B0E6
XINX 96, 214, $B389
XIO (See also XXIO, :SXIO) 99-100, 238
XIRTS 96, 214, $B3A1
XISTR 96, 213, $B35E
XLET 205, 189, $AAE0
XLIST 51, 86-87, 216, $B483
XLOAD 72, 83-84, 236, $BAFB
XLOCATE 92, 240, $BC95
XLPRINT 98-99, 216, $B464
XNEW 109, 220, 147, $A00C
XNEXT 78-79, 222, $B6CF
XNOTE 200, 239, SBC36
XON 80, 226, $B7ED
XOPEN 99, 238, $BBEB
XOP1 99, 238, $BBED
XPAASN 197, $AD5F
XPABS 206, $B0AE
XPACOM 197, $AD79
XPALPRN 198, $AD86
XPAND 195, $ACE3
XPASC 204, $B012
XPATN 207, $B12F
XPCHR 205, SB067
XPCOS 207, $B125
XPDIV 194, $ACA8
XPDLPRN 197, $AD82
XPEOL 215, $B446
XPEOS 98, 215, $B446
XPEQ 195, $ACDC
XPEXP 208, $B14D
XPFRE 204, $AFEB
XPGE 195, $ACD5
XPGT 195, $ACCC
XPINT 206, $B0DD
XPL10 208, $B143
XPLE 195, $ACB5
XPLEN 203, SAFCA
XPLOG 208, $B139
XPLOT 92, 234, $BA76
XPLT 195, $ACC5
XPMINUS 194, $AC8D
XPMUL 69, 194, SAC96
XPNE 195, $ACBE
XPNOT 195, SACF9
XPOINT 200, 239, $BC4D
XPOKE 205, 211, $B24C
XPOP 80, 227, $B841
XPOR 195, $ACEE
XPOS 92, 233, $BA16
XPPDL (See also :GRF) 204, $B022
XPPEEK 203, $AFE1
XPPLUS 194, $AC84
XPPOWER 208, $B165
XPPTRIG (See also :GRF) 204, $B02A
XPR0 98, 214, $B3BE
XPRINT 86, 97-98, 214, $B3B6
XPRIOD 98, 215, $B437
XPRND 206, $B08B
XPRPRN 197, $AD7B
XPRTN 98, 215, $B458
XPSEQ 195, $ACDC
XPSGE 195, $ACD5
XPSGN 196, $AD19
XPSGT 195, $ACCC
XPSIN 207, $B11B
XPSLE 195, $ACB5
XPSLPRN 199, $AE26
XPSLT 195, $ACC5
XPSNE 195, $ACBE
XPSQR 208, $B157
XPSTICK (See also :GRF) 204, $B026
XPSTR 205, $B049
:XPSTR98, 215, $B3F8
XPSTRIG (See also :GRF) 204, $B02E
XPSxxxx (i.e., string operator execution
routines) 195
XPTAB 98
XPUMINUS 194, Appendix B, $ACA8
295
Index
XPUPLUS 194, $ACB4
XPUSR 206, $B0BA
XPUT 99, 239, $BC72
XPVAL 204, $B000
XPxxxx (i.e., operator and function
execution routines) 69, 194-97,
203-9
XRAD 105, 211, $B266
XRD3 96, 212, $B2D0
XREAD 103-4, 211, $B283
XREM 206, 185, $A9E7
XREST 104, 211, $B26B
XRTN 79, 87, 104, 223, $B719
XRUN 51, 71-73, 224, $B74D
XSAASN 200, $AEA3
XSAVE 82-83, 237, $BB5D
XSETCOLOR 91-92, 232, $B9B7
XSOUND 93, 232, $B9DD
XSPV 200, $AE96
XSTATUS 100, 239, $BC28
XSTOP50, 72-72, 96, 225, $B793
XTRAP 76, 225, $B7E1
XTRUE 195, $AD05
XXIO 99, 238, $BBE5
i/ index 69-70 ^
z
Z = [X-C]/[X + C] (See also XFORM)
269-70
zero default with DIM 127
zero page
floating point work area 143
pointers 20, 110, 143-44
RAM locations 144 dm k
ZFP 143, $00D2
ZICB 143, $0020
ZPADEC 203, $AFBC •*
ZPG1 143, $0080
ZVAR229 / $B8C0 _
296
If you've enjoyed the articles in this book, you'll find the
same style and quality in every monthly issue of COMPUTE!
Magazine. Use this form to order your subscription to
COMPUTE!
For Fastest Service,
Call Our Toll-Free US Order Line
800-334-0868
In NC call 919-275-9809
COMPUTE!
P.O. Box 5406
Greensboro, NC 27403
My Computer Is:
□ PET [J Apple □ Atari □VIC □Other.
. □ Don't yet have one..
□ $20.00 One Year US Subscription
□ $36.00 Two Year US Subscription
□ $54.00 Three Year US Subscription
Subscription rates outside the US:
□ $25.00 Canada
Jt $38.00 Europe, Australia, New Zealand/Air Delivery
□ $48.00 Middle East, North Africa, Central America/Air Mail
□ $68.00 Elsewhere/Air Mail
Z\ $25.00 International Surface Mail (lengthy, unreliable delivery)
Name
Address
City
State
Zip
Country
Payment must be in US Funds drawn on a US Bank; International Money
Order, or charge card.
□ Payment Enclosed □ VISA
□ MasterCard □ American Express
Ace t. No. Expires /
297
COMPUTE! Books
P.O. Box 5406 Greensboro, NC 27403
Ask your retailer for these COMPUTE! Books. If he or she
has sold out, order directly from COMPUTE!
For Fastest Service
Call Our TOLL FREE US Order Line
800-334-0868
In NC call 919-275-9809
Quantity Title
The Beginner's Guide to Buying A Personal
Computer
COMPUTED First Book of Atari
Inside Atari DOS
COMPUTEI's First Book ot PET/CBM
Programming the PET/CBM
Every Kid's First Book of Robots and
Computers
COMPUTEI's Second Book of Atari
COMPUTEI's First Book of VIC
COMPUTEI's First Book of Atari Graphics
Mapping the Atari
HomeEnergyApplicationsOnYour
Personal Computer
Machine Language for Beginners
Price
$ 3.95"
$12.95*
$19.95*
$12.95*
$24.95***
$ 4.95**
$12.95*
$12.95*
$12.95*
$14.95"
$14.95*
$12.95*
' Add $2 shipping and handling. Outside US add $5 air mail; $2
surfacemail.
' ' Add $1 shipping and handling. Outside US add $5 air mail; $2
surfacemail.
"' Add $3 shipping and handling. Outside US add $10 air mail; $3
surfacemail.
Please add shipping and handling for each book
ordered.
Total enclosed or to be charged.
Total
All orders must be prepaid (money order, check, or charge). All
payments must be in US funds. NC residents add 4% sales tax.
□ Payment enclosed Please charge my: □ VISA □ MasterCard
□ American Express Acc't. No. Expires /
Name
Address
Ci1y_
State
^p_
Country
Allow 4-5 weeks for delivery.
299
7
m
m
m
m
•
•
•
•
The Atari BASIC Sourcebook
Everything You Always Wanted to Know
about the Making of a Computer Language
• When you type in BASIC programs and run them, what is
really going on inside the computer?
• How does the computer know how to handle a FOR-NEXT
loop and where it should go when it meets a RETURN?
• Where do ERROR messages come from?
• How does the computer decide which mathematical opera-
tion to perform first?
• Why do some processes take so long, when others are almost
instantaneous?
• What sometimes causes the computer to lock up when you
delete lines from your program?
• How does the computer know what to do when it sees words
and symbols like GOTO, INT, CHR$, *, + , and > ?
• How can your machine language programs take advantage
of some of the sophisticated routines in Atari BASIC?
The creators of Atari BASIC have now revealed their own
work. Even if you aren't a machine language programmer,
you'll find this book a fascinating exploration of a computer
language. Now you can understand exactly why your pro-
grams work as they do. And if you are a machine language
user, the source listing will let you see exactly where to enter
Atari BASIC to use the powerful routines built into the
language.
ISBN 0-942386-15-9
$12.95